mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190221' into staging
target-arm queue: * Model the Arm "Musca" development boards: "musca-a" and "musca-b1" * Implement the ARMv8.3-JSConv extension * v8M MPU should use background region as default, not always * Stop unintentional sign extension in pmu_init # gpg: Signature made Thu 21 Feb 2019 18:56:32 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20190221: (21 commits) hw/arm/armsse: Make 0x5... alias region work for per-CPU devices hw/arm/musca: Wire up PL011 UARTs hw/arm/musca: Wire up PL031 RTC hw/arm/musca: Add MPCs hw/arm/musca: Add PPCs hw/arm/musca.c: Implement models of the Musca-A and -B1 boards hw/arm/armsse: Allow boards to specify init-svtor hw/arm/armsse: Document SRAM_ADDR_WIDTH property in header comment hw/char/pl011: Use '0x' prefix when logging hex numbers hw/char/pl011: Support all interrupt lines hw/char/pl011: Allow use as an embedded-struct device hw/timer/pl031: Convert to using trace events hw/timer/pl031: Allow use as an embedded-struct device hw/misc/tz-ppc: Support having unused ports in the middle of the range target/arm: Implement ARMv8.3-JSConv target/arm: Rearrange Floating-point data-processing (2 regs) target/arm: Split out vfp_helper.c target/arm: Restructure disas_fp_int_conv target/arm: Stop unintentional sign extension in pmu_init target/arm: v8M MPU should use background region as default, not always ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -491,6 +491,7 @@ F: hw/sd/pl181.c
|
||||
F: hw/ssi/pl022.c
|
||||
F: include/hw/ssi/pl022.h
|
||||
F: hw/timer/pl031.c
|
||||
F: include/hw/timer/pl031.h
|
||||
F: include/hw/arm/primecell.h
|
||||
F: hw/timer/cmsdk-apb-timer.c
|
||||
F: include/hw/timer/cmsdk-apb-timer.h
|
||||
@@ -633,6 +634,12 @@ F: include/hw/misc/iotkit-sysinfo.h
|
||||
F: hw/misc/armsse-cpuid.c
|
||||
F: include/hw/misc/armsse-cpuid.h
|
||||
|
||||
Musca
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/musca.c
|
||||
|
||||
Musicpal
|
||||
M: Jan Kiszka <jan.kiszka@web.de>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
|
||||
@@ -89,6 +89,7 @@ CONFIG_TUSB6010=y
|
||||
CONFIG_IMX=y
|
||||
CONFIG_MAINSTONE=y
|
||||
CONFIG_MPS2=y
|
||||
CONFIG_MUSCA=y
|
||||
CONFIG_NSERIES=y
|
||||
CONFIG_RASPI=y
|
||||
CONFIG_REALVIEW=y
|
||||
|
||||
@@ -35,6 +35,7 @@ obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
|
||||
obj-$(CONFIG_MPS2) += mps2.o
|
||||
obj-$(CONFIG_MPS2) += mps2-tz.o
|
||||
obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o
|
||||
obj-$(CONFIG_MUSCA) += musca.o
|
||||
obj-$(CONFIG_ARMSSE) += armsse.o
|
||||
obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o
|
||||
obj-$(CONFIG_ARM_SMMUV3) += smmu-common.o smmuv3.o
|
||||
|
||||
+26
-18
@@ -110,15 +110,16 @@ static bool irq_is_common[32] = {
|
||||
/* 30, 31: reserved */
|
||||
};
|
||||
|
||||
/* Create an alias region of @size bytes starting at @base
|
||||
/*
|
||||
* Create an alias region in @container of @size bytes starting at @base
|
||||
* which mirrors the memory starting at @orig.
|
||||
*/
|
||||
static void make_alias(ARMSSE *s, MemoryRegion *mr, const char *name,
|
||||
hwaddr base, hwaddr size, hwaddr orig)
|
||||
static void make_alias(ARMSSE *s, MemoryRegion *mr, MemoryRegion *container,
|
||||
const char *name, hwaddr base, hwaddr size, hwaddr orig)
|
||||
{
|
||||
memory_region_init_alias(mr, NULL, name, &s->container, orig, size);
|
||||
memory_region_init_alias(mr, NULL, name, container, orig, size);
|
||||
/* The alias is even lower priority than unimplemented_device regions */
|
||||
memory_region_add_subregion_overlap(&s->container, base, mr, -1500);
|
||||
memory_region_add_subregion_overlap(container, base, mr, -1500);
|
||||
}
|
||||
|
||||
static void irq_status_forwarder(void *opaque, int n, int level)
|
||||
@@ -505,11 +506,10 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
* the INITSVTOR* registers before powering up the CPUs in any case,
|
||||
* so the hardware's default value doesn't matter. QEMU doesn't emulate
|
||||
* the control processor, so instead we behave in the way that the
|
||||
* firmware does. All boards currently known about have firmware that
|
||||
* sets the INITSVTOR0 and INITSVTOR1 registers to 0x10000000, like the
|
||||
* IoTKit default. We can make this more configurable if necessary.
|
||||
* firmware does. The initial value is configurable by the board code
|
||||
* to match whatever its firmware does.
|
||||
*/
|
||||
qdev_prop_set_uint32(cpudev, "init-svtor", 0x10000000);
|
||||
qdev_prop_set_uint32(cpudev, "init-svtor", s->init_svtor);
|
||||
/*
|
||||
* Start all CPUs except CPU0 powered down. In real hardware it is
|
||||
* a configurable property of the SSE-200 which CPUs start powered up
|
||||
@@ -608,16 +608,21 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
/* Set up the big aliases first */
|
||||
make_alias(s, &s->alias1, "alias 1", 0x10000000, 0x10000000, 0x00000000);
|
||||
make_alias(s, &s->alias2, "alias 2", 0x30000000, 0x10000000, 0x20000000);
|
||||
make_alias(s, &s->alias1, &s->container, "alias 1",
|
||||
0x10000000, 0x10000000, 0x00000000);
|
||||
make_alias(s, &s->alias2, &s->container,
|
||||
"alias 2", 0x30000000, 0x10000000, 0x20000000);
|
||||
/* The 0x50000000..0x5fffffff region is not a pure alias: it has
|
||||
* a few extra devices that only appear there (generally the
|
||||
* control interfaces for the protection controllers).
|
||||
* We implement this by mapping those devices over the top of this
|
||||
* alias MR at a higher priority.
|
||||
* alias MR at a higher priority. Some of the devices in this range
|
||||
* are per-CPU, so we must put this alias in the per-cpu containers.
|
||||
*/
|
||||
make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000);
|
||||
|
||||
for (i = 0; i < info->num_cpus; i++) {
|
||||
make_alias(s, &s->alias3[i], &s->cpu_container[i],
|
||||
"alias 3", 0x50000000, 0x10000000, 0x40000000);
|
||||
}
|
||||
|
||||
/* Security controller */
|
||||
object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err);
|
||||
@@ -762,26 +767,28 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
if (info->has_mhus) {
|
||||
for (i = 0; i < ARRAY_SIZE(s->mhu); i++) {
|
||||
char *name = g_strdup_printf("MHU%d", i);
|
||||
char *port = g_strdup_printf("port[%d]", i + 3);
|
||||
char *name;
|
||||
char *port;
|
||||
|
||||
name = g_strdup_printf("MHU%d", i);
|
||||
qdev_prop_set_string(DEVICE(&s->mhu[i]), "name", name);
|
||||
qdev_prop_set_uint64(DEVICE(&s->mhu[i]), "size", 0x1000);
|
||||
object_property_set_bool(OBJECT(&s->mhu[i]), true,
|
||||
"realized", &err);
|
||||
g_free(name);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
port = g_strdup_printf("port[%d]", i + 3);
|
||||
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mhu[i]), 0);
|
||||
object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr),
|
||||
port, &err);
|
||||
g_free(port);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
g_free(name);
|
||||
g_free(port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1185,6 +1192,7 @@ static Property armsse_properties[] = {
|
||||
DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
|
||||
DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0),
|
||||
DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
|
||||
DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
|
||||
+669
File diff suppressed because it is too large
Load Diff
+48
-33
@@ -7,40 +7,24 @@
|
||||
* This code is licensed under the GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* QEMU interface:
|
||||
* + sysbus MMIO region 0: device registers
|
||||
* + sysbus IRQ 0: UARTINTR (combined interrupt line)
|
||||
* + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
|
||||
* + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
|
||||
* + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
|
||||
* + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
|
||||
* + sysbus IRQ 5: UARTEINTR (error interrupt line)
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/char/pl011.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define TYPE_PL011 "pl011"
|
||||
#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011)
|
||||
|
||||
typedef struct PL011State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint32_t readbuff;
|
||||
uint32_t flags;
|
||||
uint32_t lcr;
|
||||
uint32_t rsr;
|
||||
uint32_t cr;
|
||||
uint32_t dmacr;
|
||||
uint32_t int_enabled;
|
||||
uint32_t int_level;
|
||||
uint32_t read_fifo[16];
|
||||
uint32_t ilpr;
|
||||
uint32_t ibrd;
|
||||
uint32_t fbrd;
|
||||
uint32_t ifl;
|
||||
int read_pos;
|
||||
int read_count;
|
||||
int read_trigger;
|
||||
CharBackend chr;
|
||||
qemu_irq irq;
|
||||
const unsigned char *id;
|
||||
} PL011State;
|
||||
|
||||
#define PL011_INT_TX 0x20
|
||||
#define PL011_INT_RX 0x10
|
||||
|
||||
@@ -49,18 +33,46 @@ typedef struct PL011State {
|
||||
#define PL011_FLAG_TXFF 0x20
|
||||
#define PL011_FLAG_RXFE 0x10
|
||||
|
||||
/* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
|
||||
#define INT_OE (1 << 10)
|
||||
#define INT_BE (1 << 9)
|
||||
#define INT_PE (1 << 8)
|
||||
#define INT_FE (1 << 7)
|
||||
#define INT_RT (1 << 6)
|
||||
#define INT_TX (1 << 5)
|
||||
#define INT_RX (1 << 4)
|
||||
#define INT_DSR (1 << 3)
|
||||
#define INT_DCD (1 << 2)
|
||||
#define INT_CTS (1 << 1)
|
||||
#define INT_RI (1 << 0)
|
||||
#define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
|
||||
#define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
|
||||
|
||||
static const unsigned char pl011_id_arm[8] =
|
||||
{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
|
||||
static const unsigned char pl011_id_luminary[8] =
|
||||
{ 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
|
||||
|
||||
/* Which bits in the interrupt status matter for each outbound IRQ line ? */
|
||||
static const uint32_t irqmask[] = {
|
||||
INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
|
||||
INT_RX,
|
||||
INT_TX,
|
||||
INT_RT,
|
||||
INT_MS,
|
||||
INT_E,
|
||||
};
|
||||
|
||||
static void pl011_update(PL011State *s)
|
||||
{
|
||||
uint32_t flags;
|
||||
int i;
|
||||
|
||||
flags = s->int_level & s->int_enabled;
|
||||
trace_pl011_irq_state(flags != 0);
|
||||
qemu_set_irq(s->irq, flags != 0);
|
||||
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
|
||||
qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pl011_read(void *opaque, hwaddr offset,
|
||||
@@ -131,7 +143,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl011_read: Bad offset %x\n", (int)offset);
|
||||
"pl011_read: Bad offset 0x%x\n", (int)offset);
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
@@ -220,7 +232,7 @@ static void pl011_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl011_write: Bad offset %x\n", (int)offset);
|
||||
"pl011_write: Bad offset 0x%x\n", (int)offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,10 +323,13 @@ static void pl011_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
PL011State *s = PL011(obj);
|
||||
int i;
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
|
||||
sysbus_init_irq(sbd, &s->irq[i]);
|
||||
}
|
||||
|
||||
s->read_trigger = 1;
|
||||
s->ifl = 0x12;
|
||||
@@ -357,7 +372,7 @@ static void pl011_luminary_init(Object *obj)
|
||||
}
|
||||
|
||||
static const TypeInfo pl011_luminary_info = {
|
||||
.name = "pl011_luminary",
|
||||
.name = TYPE_PL011_LUMINARY,
|
||||
.parent = TYPE_PL011,
|
||||
.instance_init = pl011_luminary_init,
|
||||
};
|
||||
|
||||
@@ -181,6 +181,21 @@ static const MemoryRegionOps tz_ppc_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static bool tz_ppc_dummy_accepts(void *opaque, hwaddr addr,
|
||||
unsigned size, bool is_write,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
/*
|
||||
* Board code should never map the upstream end of an unused port,
|
||||
* so we should never try to make a memory access to it.
|
||||
*/
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static const MemoryRegionOps tz_ppc_dummy_ops = {
|
||||
.valid.accepts = tz_ppc_dummy_accepts,
|
||||
};
|
||||
|
||||
static void tz_ppc_reset(DeviceState *dev)
|
||||
{
|
||||
TZPPC *s = TZ_PPC(dev);
|
||||
@@ -210,16 +225,33 @@ static void tz_ppc_realize(DeviceState *dev, Error **errp)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
TZPPC *s = TZ_PPC(dev);
|
||||
int i;
|
||||
int max_port = 0;
|
||||
|
||||
/* We can't create the upstream end of the port until realize,
|
||||
* as we don't know the size of the MR used as the downstream until then.
|
||||
*/
|
||||
for (i = 0; i < TZ_NUM_PORTS; i++) {
|
||||
if (s->port[i].downstream) {
|
||||
max_port = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= max_port; i++) {
|
||||
TZPPCPort *port = &s->port[i];
|
||||
char *name;
|
||||
uint64_t size;
|
||||
|
||||
if (!port->downstream) {
|
||||
/*
|
||||
* Create dummy sysbus MMIO region so the sysbus region
|
||||
* numbering doesn't get out of sync with the port numbers.
|
||||
* The size is entirely arbitrary.
|
||||
*/
|
||||
name = g_strdup_printf("tz-ppc-dummy-port[%d]", i);
|
||||
memory_region_init_io(&port->upstream, obj, &tz_ppc_dummy_ops,
|
||||
port, name, 0x10000);
|
||||
sysbus_init_mmio(sbd, &port->upstream);
|
||||
g_free(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+31
-49
@@ -12,20 +12,13 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/timer/pl031.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
//#define DEBUG_PL031
|
||||
|
||||
#ifdef DEBUG_PL031
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) do {} while(0)
|
||||
#endif
|
||||
#include "trace.h"
|
||||
|
||||
#define RTC_DR 0x00 /* Data read register */
|
||||
#define RTC_MR 0x04 /* Match register */
|
||||
@@ -36,30 +29,6 @@ do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#define RTC_MIS 0x18 /* Masked interrupt status register */
|
||||
#define RTC_ICR 0x1c /* Interrupt clear register */
|
||||
|
||||
#define TYPE_PL031 "pl031"
|
||||
#define PL031(obj) OBJECT_CHECK(PL031State, (obj), TYPE_PL031)
|
||||
|
||||
typedef struct PL031State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
QEMUTimer *timer;
|
||||
qemu_irq irq;
|
||||
|
||||
/* Needed to preserve the tick_count across migration, even if the
|
||||
* absolute value of the rtc_clock is different on the source and
|
||||
* destination.
|
||||
*/
|
||||
uint32_t tick_offset_vmstate;
|
||||
uint32_t tick_offset;
|
||||
|
||||
uint32_t mr;
|
||||
uint32_t lr;
|
||||
uint32_t cr;
|
||||
uint32_t im;
|
||||
uint32_t is;
|
||||
} PL031State;
|
||||
|
||||
static const unsigned char pl031_id[] = {
|
||||
0x31, 0x10, 0x14, 0x00, /* Device ID */
|
||||
0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */
|
||||
@@ -67,7 +36,10 @@ static const unsigned char pl031_id[] = {
|
||||
|
||||
static void pl031_update(PL031State *s)
|
||||
{
|
||||
qemu_set_irq(s->irq, s->is & s->im);
|
||||
uint32_t flags = s->is & s->im;
|
||||
|
||||
trace_pl031_irq_state(flags);
|
||||
qemu_set_irq(s->irq, flags);
|
||||
}
|
||||
|
||||
static void pl031_interrupt(void * opaque)
|
||||
@@ -75,7 +47,7 @@ static void pl031_interrupt(void * opaque)
|
||||
PL031State *s = (PL031State *)opaque;
|
||||
|
||||
s->is = 1;
|
||||
DPRINTF("Alarm raised\n");
|
||||
trace_pl031_alarm_raised();
|
||||
pl031_update(s);
|
||||
}
|
||||
|
||||
@@ -92,7 +64,7 @@ static void pl031_set_alarm(PL031State *s)
|
||||
/* The timer wraps around. This subtraction also wraps in the same way,
|
||||
and gives correct results when alarm < now_ticks. */
|
||||
ticks = s->mr - pl031_get_count(s);
|
||||
DPRINTF("Alarm set in %ud ticks\n", ticks);
|
||||
trace_pl031_set_alarm(ticks);
|
||||
if (ticks == 0) {
|
||||
timer_del(s->timer);
|
||||
pl031_interrupt(s);
|
||||
@@ -106,38 +78,49 @@ static uint64_t pl031_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
PL031State *s = (PL031State *)opaque;
|
||||
|
||||
if (offset >= 0xfe0 && offset < 0x1000)
|
||||
return pl031_id[(offset - 0xfe0) >> 2];
|
||||
uint64_t r;
|
||||
|
||||
switch (offset) {
|
||||
case RTC_DR:
|
||||
return pl031_get_count(s);
|
||||
r = pl031_get_count(s);
|
||||
break;
|
||||
case RTC_MR:
|
||||
return s->mr;
|
||||
r = s->mr;
|
||||
break;
|
||||
case RTC_IMSC:
|
||||
return s->im;
|
||||
r = s->im;
|
||||
break;
|
||||
case RTC_RIS:
|
||||
return s->is;
|
||||
r = s->is;
|
||||
break;
|
||||
case RTC_LR:
|
||||
return s->lr;
|
||||
r = s->lr;
|
||||
break;
|
||||
case RTC_CR:
|
||||
/* RTC is permanently enabled. */
|
||||
return 1;
|
||||
r = 1;
|
||||
break;
|
||||
case RTC_MIS:
|
||||
return s->is & s->im;
|
||||
r = s->is & s->im;
|
||||
break;
|
||||
case 0xfe0 ... 0xfff:
|
||||
r = pl031_id[(offset - 0xfe0) >> 2];
|
||||
break;
|
||||
case RTC_ICR:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl031: read of write-only register at offset 0x%x\n",
|
||||
(int)offset);
|
||||
r = 0;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl031_read: Bad offset 0x%x\n", (int)offset);
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
trace_pl031_read(offset, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void pl031_write(void * opaque, hwaddr offset,
|
||||
@@ -145,6 +128,7 @@ static void pl031_write(void * opaque, hwaddr offset,
|
||||
{
|
||||
PL031State *s = (PL031State *)opaque;
|
||||
|
||||
trace_pl031_write(offset, value);
|
||||
|
||||
switch (offset) {
|
||||
case RTC_LR:
|
||||
@@ -157,7 +141,6 @@ static void pl031_write(void * opaque, hwaddr offset,
|
||||
break;
|
||||
case RTC_IMSC:
|
||||
s->im = value & 1;
|
||||
DPRINTF("Interrupt mask %d\n", s->im);
|
||||
pl031_update(s);
|
||||
break;
|
||||
case RTC_ICR:
|
||||
@@ -165,7 +148,6 @@ static void pl031_write(void * opaque, hwaddr offset,
|
||||
cleared when bit 0 of the written value is set. However the
|
||||
arm926e documentation (DDI0287B) states that the interrupt is
|
||||
cleared when any value is written. */
|
||||
DPRINTF("Interrupt cleared");
|
||||
s->is = 0;
|
||||
pl031_update(s);
|
||||
break;
|
||||
|
||||
@@ -77,3 +77,9 @@ xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec
|
||||
nrf51_timer_read(uint64_t addr, uint32_t value, unsigned size) "read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
|
||||
nrf51_timer_write(uint64_t addr, uint32_t value, unsigned size) "write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
|
||||
|
||||
# hw/timer/pl031.c
|
||||
pl031_irq_state(int level) "irq state %d"
|
||||
pl031_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
pl031_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
|
||||
pl031_alarm_raised(void) "alarm raised"
|
||||
pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks"
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
* being the same for both, to avoid having to have separate Property
|
||||
* lists for different variants. This restriction can be relaxed later
|
||||
* if necessary.)
|
||||
* + QOM property "SRAM_ADDR_WIDTH" sets the number of bits used for the
|
||||
* address of each SRAM bank (and thus the total amount of internal SRAM)
|
||||
* + QOM property "init-svtor" sets the initial value of the CPU SVTOR register
|
||||
* (where it expects to load the PC and SP from the vector table on reset)
|
||||
* + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts for CPU 0,
|
||||
* which are wired to its NVIC lines 32 .. n+32
|
||||
* + Named GPIO inputs "EXP_CPU1_IRQ" 0..n are the expansion interrupts for
|
||||
@@ -182,7 +186,7 @@ typedef struct ARMSSE {
|
||||
MemoryRegion cpu_container[SSE_MAX_CPUS];
|
||||
MemoryRegion alias1;
|
||||
MemoryRegion alias2;
|
||||
MemoryRegion alias3;
|
||||
MemoryRegion alias3[SSE_MAX_CPUS];
|
||||
MemoryRegion sram[MAX_SRAM_BANKS];
|
||||
|
||||
qemu_irq *exp_irqs[SSE_MAX_CPUS];
|
||||
@@ -202,6 +206,7 @@ typedef struct ARMSSE {
|
||||
uint32_t exp_numirq;
|
||||
uint32_t mainclk_frq;
|
||||
uint32_t sram_addr_width;
|
||||
uint32_t init_svtor;
|
||||
} ARMSSE;
|
||||
|
||||
typedef struct ARMSSEInfo ARMSSEInfo;
|
||||
|
||||
@@ -15,6 +15,40 @@
|
||||
#ifndef HW_PL011_H
|
||||
#define HW_PL011_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "chardev/char-fe.h"
|
||||
|
||||
#define TYPE_PL011 "pl011"
|
||||
#define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011)
|
||||
|
||||
/* This shares the same struct (and cast macro) as the base pl011 device */
|
||||
#define TYPE_PL011_LUMINARY "pl011_luminary"
|
||||
|
||||
typedef struct PL011State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint32_t readbuff;
|
||||
uint32_t flags;
|
||||
uint32_t lcr;
|
||||
uint32_t rsr;
|
||||
uint32_t cr;
|
||||
uint32_t dmacr;
|
||||
uint32_t int_enabled;
|
||||
uint32_t int_level;
|
||||
uint32_t read_fifo[16];
|
||||
uint32_t ilpr;
|
||||
uint32_t ibrd;
|
||||
uint32_t fbrd;
|
||||
uint32_t ifl;
|
||||
int read_pos;
|
||||
int read_count;
|
||||
int read_trigger;
|
||||
CharBackend chr;
|
||||
qemu_irq irq[6];
|
||||
const unsigned char *id;
|
||||
} PL011State;
|
||||
|
||||
static inline DeviceState *pl011_create(hwaddr addr,
|
||||
qemu_irq irq,
|
||||
Chardev *chr)
|
||||
|
||||
@@ -38,7 +38,13 @@
|
||||
*
|
||||
* QEMU interface:
|
||||
* + sysbus MMIO regions 0..15: MemoryRegions defining the upstream end
|
||||
* of each of the 16 ports of the PPC
|
||||
* of each of the 16 ports of the PPC. When a port is unused (i.e. no
|
||||
* downstream MemoryRegion is connected to it) at the end of the 0..15
|
||||
* range then no sysbus MMIO region is created for its upstream. When an
|
||||
* unused port lies in the middle of the range with other used ports at
|
||||
* higher port numbers, a dummy MMIO region is created to ensure that
|
||||
* port N's upstream is always sysbus MMIO region N. Dummy regions should
|
||||
* not be mapped, and will assert if any access is made to them.
|
||||
* + Property "port[0..15]": MemoryRegion defining the downstream device(s)
|
||||
* for each of the 16 ports of the PPC
|
||||
* + Named GPIO inputs "cfg_nonsec[0..15]": set to 1 if the port should be
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ARM AMBA PrimeCell PL031 RTC
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef HW_TIMER_PL031
|
||||
#define HW_TIMER_PL031
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_PL031 "pl031"
|
||||
#define PL031(obj) OBJECT_CHECK(PL031State, (obj), TYPE_PL031)
|
||||
|
||||
typedef struct PL031State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
QEMUTimer *timer;
|
||||
qemu_irq irq;
|
||||
|
||||
/*
|
||||
* Needed to preserve the tick_count across migration, even if the
|
||||
* absolute value of the rtc_clock is different on the source and
|
||||
* destination.
|
||||
*/
|
||||
uint32_t tick_offset_vmstate;
|
||||
uint32_t tick_offset;
|
||||
|
||||
uint32_t mr;
|
||||
uint32_t lr;
|
||||
uint32_t cr;
|
||||
uint32_t im;
|
||||
uint32_t is;
|
||||
} PL031State;
|
||||
|
||||
#endif
|
||||
@@ -5,7 +5,7 @@ obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
|
||||
obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||
obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o
|
||||
obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
|
||||
obj-y += gdbstub.o
|
||||
obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
|
||||
obj-$(TARGET_AARCH64) += pauth_helper.o
|
||||
|
||||
@@ -2001,6 +2001,7 @@ static void arm_max_initfn(Object *obj)
|
||||
cpu->isar.id_isar5 = t;
|
||||
|
||||
t = cpu->isar.id_isar6;
|
||||
t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1);
|
||||
t = FIELD_DP32(t, ID_ISAR6, DP, 1);
|
||||
cpu->isar.id_isar6 = t;
|
||||
|
||||
|
||||
@@ -3273,6 +3273,11 @@ static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id)
|
||||
return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa32_dp(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0;
|
||||
@@ -3351,6 +3356,11 @@ static inline bool isar_feature_aa64_dp(const ARMISARegisters *id)
|
||||
return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0;
|
||||
|
||||
@@ -311,6 +311,7 @@ static void aarch64_max_initfn(Object *obj)
|
||||
cpu->isar.id_aa64isar0 = t;
|
||||
|
||||
t = cpu->isar.id_aa64isar1;
|
||||
t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1);
|
||||
t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1);
|
||||
t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */
|
||||
t = FIELD_DP64(t, ID_AA64ISAR1, API, 0);
|
||||
@@ -344,6 +345,7 @@ static void aarch64_max_initfn(Object *obj)
|
||||
cpu->isar.id_isar5 = u;
|
||||
|
||||
u = cpu->isar.id_isar6;
|
||||
u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1);
|
||||
u = FIELD_DP32(u, ID_ISAR6, DP, 1);
|
||||
cpu->isar.id_isar6 = u;
|
||||
|
||||
|
||||
+6
-1066
File diff suppressed because it is too large
Load Diff
@@ -218,6 +218,9 @@ DEF_HELPER_FLAGS_2(rintd_exact, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_2(rints, TCG_CALL_NO_RWG, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_2(rintd, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||
|
||||
DEF_HELPER_FLAGS_2(vjcvt, TCG_CALL_NO_RWG, i32, f64, env)
|
||||
DEF_HELPER_FLAGS_2(fjcvtzs, TCG_CALL_NO_RWG, i64, f64, ptr)
|
||||
|
||||
/* neon_helper.c */
|
||||
DEF_HELPER_FLAGS_3(neon_qadd_u8, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_qadd_s8, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
|
||||
+75
-45
@@ -6526,6 +6526,24 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_fjcvtzs(DisasContext *s, int rd, int rn)
|
||||
{
|
||||
TCGv_i64 t = read_fp_dreg(s, rn);
|
||||
TCGv_ptr fpstatus = get_fpstatus_ptr(false);
|
||||
|
||||
gen_helper_fjcvtzs(t, t, fpstatus);
|
||||
|
||||
tcg_temp_free_ptr(fpstatus);
|
||||
|
||||
tcg_gen_ext32u_i64(cpu_reg(s, rd), t);
|
||||
tcg_gen_extrh_i64_i32(cpu_ZF, t);
|
||||
tcg_gen_movi_i32(cpu_CF, 0);
|
||||
tcg_gen_movi_i32(cpu_NF, 0);
|
||||
tcg_gen_movi_i32(cpu_VF, 0);
|
||||
|
||||
tcg_temp_free_i64(t);
|
||||
}
|
||||
|
||||
/* Floating point <-> integer conversions
|
||||
* 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
|
||||
* +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
|
||||
@@ -6541,68 +6559,80 @@ static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
|
||||
int type = extract32(insn, 22, 2);
|
||||
bool sbit = extract32(insn, 29, 1);
|
||||
bool sf = extract32(insn, 31, 1);
|
||||
bool itof = false;
|
||||
|
||||
if (sbit) {
|
||||
unallocated_encoding(s);
|
||||
return;
|
||||
goto do_unallocated;
|
||||
}
|
||||
|
||||
if (opcode > 5) {
|
||||
/* FMOV */
|
||||
bool itof = opcode & 1;
|
||||
|
||||
if (rmode >= 2) {
|
||||
unallocated_encoding(s);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sf << 3 | type << 1 | rmode) {
|
||||
case 0x0: /* 32 bit */
|
||||
case 0xa: /* 64 bit */
|
||||
case 0xd: /* 64 bit to top half of quad */
|
||||
break;
|
||||
case 0x6: /* 16-bit float, 32-bit int */
|
||||
case 0xe: /* 16-bit float, 64-bit int */
|
||||
if (dc_isar_feature(aa64_fp16, s)) {
|
||||
break;
|
||||
}
|
||||
/* fallthru */
|
||||
default:
|
||||
/* all other sf/type/rmode combinations are invalid */
|
||||
unallocated_encoding(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fp_access_check(s)) {
|
||||
return;
|
||||
}
|
||||
handle_fmov(s, rd, rn, type, itof);
|
||||
} else {
|
||||
/* actual FP conversions */
|
||||
bool itof = extract32(opcode, 1, 1);
|
||||
|
||||
if (rmode != 0 && opcode > 1) {
|
||||
unallocated_encoding(s);
|
||||
return;
|
||||
switch (opcode) {
|
||||
case 2: /* SCVTF */
|
||||
case 3: /* UCVTF */
|
||||
itof = true;
|
||||
/* fallthru */
|
||||
case 4: /* FCVTAS */
|
||||
case 5: /* FCVTAU */
|
||||
if (rmode != 0) {
|
||||
goto do_unallocated;
|
||||
}
|
||||
/* fallthru */
|
||||
case 0: /* FCVT[NPMZ]S */
|
||||
case 1: /* FCVT[NPMZ]U */
|
||||
switch (type) {
|
||||
case 0: /* float32 */
|
||||
case 1: /* float64 */
|
||||
break;
|
||||
case 3: /* float16 */
|
||||
if (dc_isar_feature(aa64_fp16, s)) {
|
||||
break;
|
||||
if (!dc_isar_feature(aa64_fp16, s)) {
|
||||
goto do_unallocated;
|
||||
}
|
||||
/* fallthru */
|
||||
break;
|
||||
default:
|
||||
unallocated_encoding(s);
|
||||
return;
|
||||
goto do_unallocated;
|
||||
}
|
||||
|
||||
if (!fp_access_check(s)) {
|
||||
return;
|
||||
}
|
||||
handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (sf << 7 | type << 5 | rmode << 3 | opcode) {
|
||||
case 0b01100110: /* FMOV half <-> 32-bit int */
|
||||
case 0b01100111:
|
||||
case 0b11100110: /* FMOV half <-> 64-bit int */
|
||||
case 0b11100111:
|
||||
if (!dc_isar_feature(aa64_fp16, s)) {
|
||||
goto do_unallocated;
|
||||
}
|
||||
/* fallthru */
|
||||
case 0b00000110: /* FMOV 32-bit */
|
||||
case 0b00000111:
|
||||
case 0b10100110: /* FMOV 64-bit */
|
||||
case 0b10100111:
|
||||
case 0b11001110: /* FMOV top half of 128-bit */
|
||||
case 0b11001111:
|
||||
if (!fp_access_check(s)) {
|
||||
return;
|
||||
}
|
||||
itof = opcode & 1;
|
||||
handle_fmov(s, rd, rn, type, itof);
|
||||
break;
|
||||
|
||||
case 0b00111110: /* FJCVTZS */
|
||||
if (!dc_isar_feature(aa64_jscvt, s)) {
|
||||
goto do_unallocated;
|
||||
} else if (fp_access_check(s)) {
|
||||
handle_fjcvtzs(s, rd, rn);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
do_unallocated:
|
||||
unallocated_encoding(s);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user