Merge remote-tracking branch 'remotes/rth/tags/pull-nios-20170124' into staging

nios2 target support

# gpg: Signature made Tue 24 Jan 2017 21:11:47 GMT
# gpg:                using RSA key 0xAD1270CC4DD0279B
# gpg: Good signature from "Richard Henderson <rth7680@gmail.com>"
# gpg:                 aka "Richard Henderson <rth@redhat.com>"
# gpg:                 aka "Richard Henderson <rth@twiddle.net>"
# Primary key fingerprint: 9CB1 8DDA F8E8 49AD 2AFC  16A4 AD12 70CC 4DD0 279B

* remotes/rth/tags/pull-nios-20170124:
  nios2: Add support for Nios-II R1
  nios2: Add Altera 10M50 GHRD emulation
  nios2: Add periodic timer emulation
  nios2: Add IIC interrupt controller emulation
  nios2: Add usermode binaries emulation
  nios2: Add disas entries
  nios2: Add architecture emulation support

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2017-01-25 13:30:23 +00:00
40 changed files with 7727 additions and 7 deletions
+8
View File
@@ -187,6 +187,14 @@ F: disas/moxie.c
F: hw/moxie/
F: default-configs/moxie-softmmu.mak
NiosII
M: Chris Wulff <crwulff@gmail.com>
M: Marek Vasut <marex@denx.de>
S: Maintained
F: target/nios2/
F: hw/nios2/
F: disas/nios2.c
OpenRISC
M: Jia Liu <proljc@gmail.com>
S: Maintained
+2
View File
@@ -63,6 +63,8 @@ int graphic_depth = 32;
#define QEMU_ARCH QEMU_ARCH_MIPS
#elif defined(TARGET_MOXIE)
#define QEMU_ARCH QEMU_ARCH_MOXIE
#elif defined(TARGET_NIOS2)
#define QEMU_ARCH QEMU_ARCH_NIOS2
#elif defined(TARGET_OPENRISC)
#define QEMU_ARCH QEMU_ARCH_OPENRISC
#elif defined(TARGET_PPC)
Vendored
+5
View File
@@ -5935,6 +5935,8 @@ case "$target_name" in
;;
moxie)
;;
nios2)
;;
or32)
TARGET_ARCH=openrisc
TARGET_BASE_ARCH=openrisc
@@ -6140,6 +6142,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
moxie*)
disas_config "MOXIE"
;;
nios2)
disas_config "NIOS2"
;;
or32)
disas_config "OPENRISC"
;;
+1
View File
@@ -0,0 +1 @@
# Default configuration for nios2-linux-user
+6
View File
@@ -0,0 +1,6 @@
# Default configuration for nios2-softmmu
CONFIG_NIOS2=y
CONFIG_SERIAL=y
CONFIG_PTIMER=y
CONFIG_ALTERA_TIMER=y
+1
View File
@@ -15,6 +15,7 @@ common-obj-$(CONFIG_IA64_DIS) += ia64.o
common-obj-$(CONFIG_M68K_DIS) += m68k.o
common-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o
common-obj-$(CONFIG_MIPS_DIS) += mips.o
common-obj-$(CONFIG_NIOS2_DIS) += nios2.o
common-obj-$(CONFIG_MOXIE_DIS) += moxie.o
common-obj-$(CONFIG_PPC_DIS) += ppc.o
common-obj-$(CONFIG_S390_DIS) += s390.o
+3534
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -41,3 +41,4 @@ obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
obj-$(CONFIG_ASPEED_SOC) += aspeed_vic.o
obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o
obj-$(CONFIG_MIPS_CPS) += mips_gic.o
obj-$(CONFIG_NIOS2) += nios2_iic.o
+103
View File
@@ -0,0 +1,103 @@
/*
* QEMU Altera Internal Interrupt Controller.
*
* Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
*
* 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.1 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/lgpl-2.1.html>
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "cpu.h"
#define TYPE_ALTERA_IIC "altera,iic"
#define ALTERA_IIC(obj) \
OBJECT_CHECK(AlteraIIC, (obj), TYPE_ALTERA_IIC)
typedef struct AlteraIIC {
SysBusDevice parent_obj;
void *cpu;
qemu_irq parent_irq;
} AlteraIIC;
static void update_irq(AlteraIIC *pv)
{
CPUNios2State *env = &((Nios2CPU *)(pv->cpu))->env;
qemu_set_irq(pv->parent_irq,
env->regs[CR_IPENDING] & env->regs[CR_IENABLE]);
}
static void irq_handler(void *opaque, int irq, int level)
{
AlteraIIC *pv = opaque;
CPUNios2State *env = &((Nios2CPU *)(pv->cpu))->env;
env->regs[CR_IPENDING] &= ~(1 << irq);
env->regs[CR_IPENDING] |= !!level << irq;
update_irq(pv);
}
static void altera_iic_init(Object *obj)
{
AlteraIIC *pv = ALTERA_IIC(obj);
qdev_init_gpio_in(DEVICE(pv), irq_handler, 32);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &pv->parent_irq);
}
static Property altera_iic_properties[] = {
DEFINE_PROP_PTR("cpu", AlteraIIC, cpu),
DEFINE_PROP_END_OF_LIST(),
};
static void altera_iic_realize(DeviceState *dev, Error **errp)
{
struct AlteraIIC *pv = ALTERA_IIC(dev);
if (!pv->cpu) {
error_setg(errp, "altera,iic: CPU not connected");
return;
}
}
static void altera_iic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = altera_iic_properties;
/* Reason: pointer property "cpu" */
dc->cannot_instantiate_with_device_add_yet = true;
dc->realize = altera_iic_realize;
}
static TypeInfo altera_iic_info = {
.name = "altera,iic",
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AlteraIIC),
.instance_init = altera_iic_init,
.class_init = altera_iic_class_init,
};
static void altera_iic_register(void)
{
type_register_static(&altera_iic_info);
}
type_init(altera_iic_register)
+126
View File
@@ -0,0 +1,126 @@
/*
* Altera 10M50 Nios2 GHRD
*
* Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com>
*
* Based on LabX device code
*
* Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
*
* 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.1 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/lgpl-2.1.html>
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/sysbus.h"
#include "hw/hw.h"
#include "hw/char/serial.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
#include "qemu/config-file.h"
#include "boot.h"
#define BINARY_DEVICE_TREE_FILE "10m50-devboard.dtb"
static void nios2_10m50_ghrd_init(MachineState *machine)
{
Nios2CPU *cpu;
DeviceState *dev;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *phys_tcm = g_new(MemoryRegion, 1);
MemoryRegion *phys_tcm_alias = g_new(MemoryRegion, 1);
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
MemoryRegion *phys_ram_alias = g_new(MemoryRegion, 1);
ram_addr_t tcm_base = 0x0;
ram_addr_t tcm_size = 0x1000; /* 1 kiB, but QEMU limit is 4 kiB */
ram_addr_t ram_base = 0x08000000;
ram_addr_t ram_size = 0x08000000;
qemu_irq *cpu_irq, irq[32];
int i;
/* Physical TCM (tb_ram_1k) with alias at 0xc0000000 */
memory_region_init_ram(phys_tcm, NULL, "nios2.tcm", tcm_size, &error_abort);
memory_region_init_alias(phys_tcm_alias, NULL, "nios2.tcm.alias",
phys_tcm, 0, tcm_size);
vmstate_register_ram_global(phys_tcm);
memory_region_add_subregion(address_space_mem, tcm_base, phys_tcm);
memory_region_add_subregion(address_space_mem, 0xc0000000 + tcm_base,
phys_tcm_alias);
/* Physical DRAM with alias at 0xc0000000 */
memory_region_init_ram(phys_ram, NULL, "nios2.ram", ram_size, &error_abort);
memory_region_init_alias(phys_ram_alias, NULL, "nios2.ram.alias",
phys_ram, 0, ram_size);
vmstate_register_ram_global(phys_ram);
memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base,
phys_ram_alias);
/* Create CPU -- FIXME */
cpu = cpu_nios2_init("nios2");
/* Register: CPU interrupt controller (PIC) */
cpu_irq = nios2_cpu_pic_init(cpu);
/* Register: Internal Interrupt Controller (IIC) */
dev = qdev_create(NULL, "altera,iic");
qdev_prop_set_ptr(dev, "cpu", cpu);
qdev_init_nofail(dev);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]);
for (i = 0; i < 32; i++) {
irq[i] = qdev_get_gpio_in(dev, i);
}
/* Register: Altera 16550 UART */
serial_mm_init(address_space_mem, 0xf8001600, 2, irq[1], 115200,
serial_hds[0], DEVICE_NATIVE_ENDIAN);
/* Register: Timer sys_clk_timer */
dev = qdev_create(NULL, "ALTR.timer");
qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xf8001440);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[0]);
/* Register: Timer sys_clk_timer_1 */
dev = qdev_create(NULL, "ALTR.timer");
qdev_prop_set_uint32(dev, "clock-frequency", 75 * 1000000);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xe0000880);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[5]);
/* Configure new exception vectors and reset CPU for it to take effect. */
cpu->reset_addr = 0xd4000000;
cpu->exception_addr = 0xc8000120;
cpu->fast_tlb_miss_addr = 0xc0000100;
nios2_load_kernel(cpu, ram_base, ram_size, machine->initrd_filename,
BINARY_DEVICE_TREE_FILE, NULL);
}
static void nios2_10m50_ghrd_machine_init(struct MachineClass *mc)
{
mc->desc = "Altera 10M50 GHRD Nios II design";
mc->init = nios2_10m50_ghrd_init;
mc->is_default = 1;
}
DEFINE_MACHINE("10m50-ghrd", nios2_10m50_ghrd_machine_init);
+1
View File
@@ -0,0 +1 @@
obj-y = boot.o cpu_pic.o 10m50_devboard.o
+223
View File
@@ -0,0 +1,223 @@
/*
* Nios2 kernel loader
*
* Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com>
*
* Based on microblaze kernel loader
*
* Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com>
* Copyright (c) 2012 PetaLogix
* Copyright (c) 2009 Edgar E. Iglesias.
*
* 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 "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "qemu-common.h"
#include "sysemu/device_tree.h"
#include "sysemu/sysemu.h"
#include "hw/loader.h"
#include "elf.h"
#include "qemu/cutils.h"
#include "boot.h"
#define NIOS2_MAGIC 0x534f494e
static struct nios2_boot_info {
void (*machine_cpu_reset)(Nios2CPU *);
uint32_t bootstrap_pc;
uint32_t cmdline;
uint32_t initrd_start;
uint32_t initrd_end;
uint32_t fdt;
} boot_info;
static void main_cpu_reset(void *opaque)
{
Nios2CPU *cpu = opaque;
CPUState *cs = CPU(cpu);
CPUNios2State *env = &cpu->env;
cpu_reset(CPU(cpu));
env->regs[R_ARG0] = NIOS2_MAGIC;
env->regs[R_ARG1] = boot_info.initrd_start;
env->regs[R_ARG2] = boot_info.fdt;
env->regs[R_ARG3] = boot_info.cmdline;
cpu_set_pc(cs, boot_info.bootstrap_pc);
if (boot_info.machine_cpu_reset) {
boot_info.machine_cpu_reset(cpu);
}
}
static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
{
return addr - 0xc0000000LL;
}
static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize,
const char *kernel_cmdline, const char *dtb_filename)
{
int fdt_size;
void *fdt = NULL;
int r;
if (dtb_filename) {
fdt = load_device_tree(dtb_filename, &fdt_size);
}
if (!fdt) {
return 0;
}
if (kernel_cmdline) {
r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
kernel_cmdline);
if (r < 0) {
fprintf(stderr, "couldn't set /chosen/bootargs\n");
}
}
if (bi.initrd_start) {
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
translate_kernel_address(NULL, bi.initrd_start));
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
translate_kernel_address(NULL, bi.initrd_end));
}
cpu_physical_memory_write(bi.fdt, fdt, fdt_size);
return fdt_size;
}
void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base,
uint32_t ramsize,
const char *initrd_filename,
const char *dtb_filename,
void (*machine_cpu_reset)(Nios2CPU *))
{
QemuOpts *machine_opts;
const char *kernel_filename;
const char *kernel_cmdline;
const char *dtb_arg;
char *filename = NULL;
machine_opts = qemu_get_machine_opts();
kernel_filename = qemu_opt_get(machine_opts, "kernel");
kernel_cmdline = qemu_opt_get(machine_opts, "append");
dtb_arg = qemu_opt_get(machine_opts, "dtb");
/* default to pcbios dtb as passed by machine_init */
if (!dtb_arg) {
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
}
boot_info.machine_cpu_reset = machine_cpu_reset;
qemu_register_reset(main_cpu_reset, cpu);
if (kernel_filename) {
int kernel_size, fdt_size;
uint64_t entry, low, high;
uint32_t base32;
int big_endian = 0;
#ifdef TARGET_WORDS_BIGENDIAN
big_endian = 1;
#endif
/* Boots a kernel elf binary. */
kernel_size = load_elf(kernel_filename, NULL, NULL,
&entry, &low, &high,
big_endian, EM_ALTERA_NIOS2, 0, 0);
base32 = entry;
if (base32 == 0xc0000000) {
kernel_size = load_elf(kernel_filename, translate_kernel_address,
NULL, &entry, NULL, NULL,
big_endian, EM_ALTERA_NIOS2, 0, 0);
}
/* Always boot into physical ram. */
boot_info.bootstrap_pc = ddr_base + 0xc0000000 + (entry & 0x07ffffff);
/* If it wasn't an ELF image, try an u-boot image. */
if (kernel_size < 0) {
hwaddr uentry, loadaddr;
kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
NULL, NULL);
boot_info.bootstrap_pc = uentry;
high = loadaddr + kernel_size;
}
/* Not an ELF image nor an u-boot image, try a RAW image. */
if (kernel_size < 0) {
kernel_size = load_image_targphys(kernel_filename, ddr_base,
ram_size);
boot_info.bootstrap_pc = ddr_base;
high = ddr_base + kernel_size;
}
high = ROUND_UP(high, 1024 * 1024);
/* If initrd is available, it goes after the kernel, aligned to 1M. */
if (initrd_filename) {
int initrd_size;
uint32_t initrd_offset;
boot_info.initrd_start = high;
initrd_offset = boot_info.initrd_start - ddr_base;
initrd_size = load_ramdisk(initrd_filename,
boot_info.initrd_start,
ram_size - initrd_offset);
if (initrd_size < 0) {
initrd_size = load_image_targphys(initrd_filename,
boot_info.initrd_start,
ram_size - initrd_offset);
}
if (initrd_size < 0) {
error_report("qemu: could not load initrd '%s'",
initrd_filename);
exit(EXIT_FAILURE);
}
high += initrd_size;
}
high = ROUND_UP(high, 4);
boot_info.initrd_end = high;
/* Device tree must be placed right after initrd (if available) */
boot_info.fdt = high;
fdt_size = nios2_load_dtb(boot_info, ram_size, kernel_cmdline,
/* Preference a -dtb argument */
dtb_arg ? dtb_arg : filename);
high += fdt_size;
/* Kernel command is at the end, 4k aligned. */
boot_info.cmdline = ROUND_UP(high, 4096);
if (kernel_cmdline && strlen(kernel_cmdline)) {
pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
}
}
g_free(filename);
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef NIOS2_BOOT_H
#define NIOS2_BOOT_H
#include "hw/hw.h"
#include "cpu.h"
void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base, uint32_t ramsize,
const char *initrd_filename, const char *dtb_filename,
void (*machine_cpu_reset)(Nios2CPU *));
#endif /* NIOS2_BOOT_H */
+70
View File
@@ -0,0 +1,70 @@
/*
* Altera Nios2 CPU PIC
*
* Copyright (c) 2016 Marek Vasut <marek.vasut@gmail.com>
*
* 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.1 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/lgpl-2.1.html>
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
#include "qemu/config-file.h"
#include "boot.h"
static void nios2_pic_cpu_handler(void *opaque, int irq, int level)
{
Nios2CPU *cpu = opaque;
CPUNios2State *env = &cpu->env;
CPUState *cs = CPU(cpu);
int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD;
if (type == CPU_INTERRUPT_HARD) {
env->irq_pending = level;
if (level && (env->regs[CR_STATUS] & CR_STATUS_PIE)) {
env->irq_pending = 0;
cpu_interrupt(cs, type);
} else if (!level) {
env->irq_pending = 0;
cpu_reset_interrupt(cs, type);
}
} else {
if (level) {
cpu_interrupt(cs, type);
} else {
cpu_reset_interrupt(cs, type);
}
}
}
void nios2_check_interrupts(CPUNios2State *env)
{
Nios2CPU *cpu = nios2_env_get_cpu(env);
CPUState *cs = CPU(cpu);
if (env->irq_pending) {
env->irq_pending = 0;
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
qemu_irq *nios2_cpu_pic_init(Nios2CPU *cpu)
{
return qemu_allocate_irqs(nios2_pic_cpu_handler, cpu, 2);
}
+1
View File
@@ -18,6 +18,7 @@ common-obj-$(CONFIG_IMX) += imx_gpt.o
common-obj-$(CONFIG_LM32) += lm32_timer.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o
obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o
+237
View File
@@ -0,0 +1,237 @@
/*
* QEMU model of the Altera timer.
*
* Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
*
* 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.1 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/lgpl-2.1.html>
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "hw/ptimer.h"
#define R_STATUS 0
#define R_CONTROL 1
#define R_PERIODL 2
#define R_PERIODH 3
#define R_SNAPL 4
#define R_SNAPH 5
#define R_MAX 6
#define STATUS_TO 0x0001
#define STATUS_RUN 0x0002
#define CONTROL_ITO 0x0001
#define CONTROL_CONT 0x0002
#define CONTROL_START 0x0004
#define CONTROL_STOP 0x0008
#define TYPE_ALTERA_TIMER "ALTR.timer"
#define ALTERA_TIMER(obj) \
OBJECT_CHECK(AlteraTimer, (obj), TYPE_ALTERA_TIMER)
typedef struct AlteraTimer {
SysBusDevice busdev;
MemoryRegion mmio;
qemu_irq irq;
uint32_t freq_hz;
QEMUBH *bh;
ptimer_state *ptimer;
uint32_t regs[R_MAX];
} AlteraTimer;
static int timer_irq_state(AlteraTimer *t)
{
bool irq = (t->regs[R_STATUS] & STATUS_TO) &&
(t->regs[R_CONTROL] & CONTROL_ITO);
return irq;
}
static uint64_t timer_read(void *opaque, hwaddr addr,
unsigned int size)
{
AlteraTimer *t = opaque;
uint64_t r = 0;
addr >>= 2;
switch (addr) {
case R_CONTROL:
r = t->regs[R_CONTROL] & (CONTROL_ITO | CONTROL_CONT);
break;
default:
if (addr < ARRAY_SIZE(t->regs)) {
r = t->regs[addr];
}
break;
}
return r;
}
static void timer_write(void *opaque, hwaddr addr,
uint64_t value, unsigned int size)
{
AlteraTimer *t = opaque;
uint64_t tvalue;
uint32_t count = 0;
int irqState = timer_irq_state(t);
addr >>= 2;
switch (addr) {
case R_STATUS:
/* The timeout bit is cleared by writing the status register. */
t->regs[R_STATUS] &= ~STATUS_TO;
break;
case R_CONTROL:
t->regs[R_CONTROL] = value & (CONTROL_ITO | CONTROL_CONT);
if ((value & CONTROL_START) &&
!(t->regs[R_STATUS] & STATUS_RUN)) {
ptimer_run(t->ptimer, 1);
t->regs[R_STATUS] |= STATUS_RUN;
}
if ((value & CONTROL_STOP) && (t->regs[R_STATUS] & STATUS_RUN)) {
ptimer_stop(t->ptimer);
t->regs[R_STATUS] &= ~STATUS_RUN;
}
break;
case R_PERIODL:
case R_PERIODH:
t->regs[addr] = value & 0xFFFF;
if (t->regs[R_STATUS] & STATUS_RUN) {
ptimer_stop(t->ptimer);
t->regs[R_STATUS] &= ~STATUS_RUN;
}
tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL];
ptimer_set_limit(t->ptimer, tvalue + 1, 1);
break;
case R_SNAPL:
case R_SNAPH:
count = ptimer_get_count(t->ptimer);
t->regs[R_SNAPL] = count & 0xFFFF;
t->regs[R_SNAPH] = count >> 16;
break;
default:
break;
}
if (irqState != timer_irq_state(t)) {
qemu_set_irq(t->irq, timer_irq_state(t));
}
}
static const MemoryRegionOps timer_ops = {
.read = timer_read,
.write = timer_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4
}
};
static void timer_hit(void *opaque)
{
AlteraTimer *t = opaque;
const uint64_t tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL];
t->regs[R_STATUS] |= STATUS_TO;
ptimer_set_limit(t->ptimer, tvalue + 1, 1);
if (!(t->regs[R_CONTROL] & CONTROL_CONT)) {
t->regs[R_STATUS] &= ~STATUS_RUN;
ptimer_set_count(t->ptimer, tvalue);
} else {
ptimer_run(t->ptimer, 1);
}
qemu_set_irq(t->irq, timer_irq_state(t));
}
static void altera_timer_realize(DeviceState *dev, Error **errp)
{
AlteraTimer *t = ALTERA_TIMER(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
if (t->freq_hz == 0) {
error_setg(errp, "\"clock-frequency\" property must be provided.");
return;
}
t->bh = qemu_bh_new(timer_hit, t);
t->ptimer = ptimer_init(t->bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(t->ptimer, t->freq_hz);
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
TYPE_ALTERA_TIMER, R_MAX * sizeof(uint32_t));
sysbus_init_mmio(sbd, &t->mmio);
}
static void altera_timer_init(Object *obj)
{
AlteraTimer *t = ALTERA_TIMER(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
sysbus_init_irq(sbd, &t->irq);
}
static void altera_timer_reset(DeviceState *dev)
{
AlteraTimer *t = ALTERA_TIMER(dev);
ptimer_stop(t->ptimer);
ptimer_set_limit(t->ptimer, 0xffffffff, 1);
memset(t->regs, 0, ARRAY_SIZE(t->regs));
}
static Property altera_timer_properties[] = {
DEFINE_PROP_UINT32("clock-frequency", AlteraTimer, freq_hz, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void altera_timer_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = altera_timer_realize;
dc->props = altera_timer_properties;
dc->reset = altera_timer_reset;
}
static const TypeInfo altera_timer_info = {
.name = TYPE_ALTERA_TIMER,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AlteraTimer),
.instance_init = altera_timer_init,
.class_init = altera_timer_class_init,
};
static void altera_timer_register(void)
{
type_register_static(&altera_timer_info);
}
type_init(altera_timer_register)
+6
View File
@@ -222,6 +222,10 @@ enum bfd_architecture
bfd_arch_ia64, /* HP/Intel ia64 */
#define bfd_mach_ia64_elf64 64
#define bfd_mach_ia64_elf32 32
bfd_arch_nios2, /* Nios II */
#define bfd_mach_nios2 0
#define bfd_mach_nios2r1 1
#define bfd_mach_nios2r2 2
bfd_arch_lm32, /* Lattice Mico32 */
#define bfd_mach_lm32 1
bfd_arch_last
@@ -415,6 +419,8 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*);
int print_insn_microblaze (bfd_vma, disassemble_info*);
int print_insn_ia64 (bfd_vma, disassemble_info*);
int print_insn_lm32 (bfd_vma, disassemble_info*);
int print_insn_big_nios2 (bfd_vma, disassemble_info*);
int print_insn_little_nios2 (bfd_vma, disassemble_info*);
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
+2
View File
@@ -126,6 +126,8 @@ typedef int64_t Elf64_Sxword;
*/
#define EM_S390_OLD 0xA390
#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */
#define EM_MICROBLAZE 189
#define EM_MICROBLAZE_OLD 0xBAAB
+1
View File
@@ -23,6 +23,7 @@ enum {
QEMU_ARCH_UNICORE32 = (1 << 14),
QEMU_ARCH_MOXIE = (1 << 15),
QEMU_ARCH_TRICORE = (1 << 16),
QEMU_ARCH_NIOS2 = (1 << 17),
};
extern const uint32_t arch_type;
+57
View File
@@ -967,6 +967,63 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env
#endif /* TARGET_MICROBLAZE */
#ifdef TARGET_NIOS2
#define ELF_START_MMAP 0x80000000
#define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_ALTERA_NIOS2
static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
regs->ea = infop->entry;
regs->sp = infop->start_stack;
regs->estatus = 0x3;
}
#define ELF_EXEC_PAGESIZE 4096
#define USE_ELF_CORE_DUMP
#define ELF_NREG 49
typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
/* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */
static void elf_core_copy_regs(target_elf_gregset_t *regs,
const CPUNios2State *env)
{
int i;
(*regs)[0] = -1;
for (i = 1; i < 8; i++) /* r0-r7 */
(*regs)[i] = tswapreg(env->regs[i + 7]);
for (i = 8; i < 16; i++) /* r8-r15 */
(*regs)[i] = tswapreg(env->regs[i - 8]);
for (i = 16; i < 24; i++) /* r16-r23 */
(*regs)[i] = tswapreg(env->regs[i + 7]);
(*regs)[24] = -1; /* R_ET */
(*regs)[25] = -1; /* R_BT */
(*regs)[26] = tswapreg(env->regs[R_GP]);
(*regs)[27] = tswapreg(env->regs[R_SP]);
(*regs)[28] = tswapreg(env->regs[R_FP]);
(*regs)[29] = tswapreg(env->regs[R_EA]);
(*regs)[30] = -1; /* R_SSTATUS */
(*regs)[31] = tswapreg(env->regs[R_RA]);
(*regs)[32] = tswapreg(env->regs[R_PC]);
(*regs)[33] = -1; /* R_STATUS */
(*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
for (i = 35; i < 49; i++) /* ... */
(*regs)[i] = -1;
}
#endif /* TARGET_NIOS2 */
#ifdef TARGET_OPENRISC
#define ELF_START_MMAP 0x08000000

Some files were not shown because too many files have changed in this diff Show More