target-arm queue:
* Revert and correctly fix refactoring of unallocated_encoding() * Take exceptions on ATS instructions when needed * aspeed/timer: Provide back-pressure information for short periods * memory: Remove unused memory_region_iommu_replay_all() * hw/arm/smmuv3: Log a guest error when decoding an invalid STE * hw/arm/smmuv3: Remove spurious error messages on IOVA invalidations * target/arm: Fix SMMLS argument order * hw/arm: Use ARM_CPU_TYPE_NAME() macro when appropriate * hw/arm: Correct reference counting for creation of various objects * includes: remove stale [smp|max]_cpus externs * tcg/README: fix typo * atomic_template: fix indentation in GEN_ATOMIC_HELPER * include/exec/cpu-defs.h: fix typo * target/arm: Free TCG temps in trans_VMOV_64_sp() * target/arm: Don't abort on M-profile exception return in linux-user mode -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl1uiDcZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3uaaD/9C/1Tkn4nkeZLfVZIT/xJ2 ERCSJhE4N7VvPFkW7Qr9hQAV+M8FGrMRdY769vgNOBmFle7EODclD5GlMeetPwIb Trot8eH51LEcXz00wXQZFF5k1/G8ccf7CdNLYBUvS/Bu/GipchELe1mVdjJ283mU Fgl+pIFq2jjnqP5mAoO9pjY2fSq/X2it7quDLEynJixwCgIKIpuWnhVJW+qoOpCc Z1vV1Zq9xGGPj8GGtWQx0Rxpl8U1IsZdp81TtUFo+zuCjk0CY0eGYEZDVAtaJepU yQHzR9EPq/cBSFY2DKlhDu3r3xdrpdA45pkbTC8WMh08WbtKIdNDzdjqow5KACRX w+jZ3EVg+vL4WYxIlWMn43QUO+7D/3+qu5SHBOCOoVeVi/8XxQ8+CH9UUtX31kLH K0WJzF2WNJTQGP1oNd9jTEKot3JlEUDqK6Z/vFD0XV4ijbwieTW9A6KPIPiuzyIq v7YyO1L+0Xuk96jOsl8J3u5qh1GEqrPam8b1McPFOj89LDp3PdoH1iBQRHr5Uujt Ad/JKwAqo9nEJq/o5PL2W8fmuR3Nkb54Gu+k29HRZeHC7crf6k6OZT/T525oUNFI lDCTq37bTH3RU29S5lWpGlQWcGBXhDoS8QHVE2g7tGkoaUBVKi8E2GyQs1zkakYn SsY+zUc0Sowz2vccOAekvw== =N0jC -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190903' into staging target-arm queue: * Revert and correctly fix refactoring of unallocated_encoding() * Take exceptions on ATS instructions when needed * aspeed/timer: Provide back-pressure information for short periods * memory: Remove unused memory_region_iommu_replay_all() * hw/arm/smmuv3: Log a guest error when decoding an invalid STE * hw/arm/smmuv3: Remove spurious error messages on IOVA invalidations * target/arm: Fix SMMLS argument order * hw/arm: Use ARM_CPU_TYPE_NAME() macro when appropriate * hw/arm: Correct reference counting for creation of various objects * includes: remove stale [smp|max]_cpus externs * tcg/README: fix typo * atomic_template: fix indentation in GEN_ATOMIC_HELPER * include/exec/cpu-defs.h: fix typo * target/arm: Free TCG temps in trans_VMOV_64_sp() * target/arm: Don't abort on M-profile exception return in linux-user mode # gpg: Signature made Tue 03 Sep 2019 16:35:19 BST # 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-20190903: (21 commits) target/arm: Don't abort on M-profile exception return in linux-user mode target/arm: Free TCG temps in trans_VMOV_64_sp() include/exec/cpu-defs.h: fix typo atomic_template: fix indentation in GEN_ATOMIC_HELPER tcg/README: fix typo s/afterwise/afterwards/ includes: remove stale [smp|max]_cpus externs hw/net/xilinx_axi: Use object_initialize_child for correct ref. counting hw/dma/xilinx_axi: Use object_initialize_child for correct ref. counting hw/arm/fsl-imx: Add the cpu as child of the SoC object hw/arm: Use sysbus_init_child_obj for correct reference counting hw/arm: Use object_initialize_child for correct reference counting hw/arm: Use ARM_CPU_TYPE_NAME() macro when appropriate target/arm: Fix SMMLS argument order hw/arm/smmuv3: Remove spurious error messages on IOVA invalidations hw/arm/smmuv3: Log a guest error when decoding an invalid STE memory: Remove unused memory_region_iommu_replay_all() aspeed/timer: Provide back-pressure information for short periods target/arm: Take exceptions on ATS instructions when needed target/arm: Allow ARMCPRegInfo read/write functions to throw exceptions target/arm: Factor out unallocated_encoding for aarch32 ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
3c8153d3f5
|
@ -284,7 +284,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
|||
|
||||
#define GEN_ATOMIC_HELPER(X) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE val EXTRA_ARGS) \
|
||||
ABI_TYPE val EXTRA_ARGS) \
|
||||
{ \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
|
|
|
@ -30,7 +30,8 @@ static void aw_a10_init(Object *obj)
|
|||
AwA10State *s = AW_A10(obj);
|
||||
|
||||
object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
|
||||
"cortex-a8-" TYPE_ARM_CPU, &error_abort, NULL);
|
||||
ARM_CPU_TYPE_NAME("cortex-a8"),
|
||||
&error_abort, NULL);
|
||||
|
||||
sysbus_init_child_obj(obj, "intc", &s->intc, sizeof(s->intc),
|
||||
TYPE_AW_A10_PIC);
|
||||
|
|
|
@ -81,7 +81,8 @@ static void cubieboard_init(MachineState *machine)
|
|||
|
||||
static void cubieboard_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "cubietech cubieboard";
|
||||
mc->desc = "cubietech cubieboard (Cortex-A9)";
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
|
||||
mc->init = cubieboard_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
|
|
|
@ -37,7 +37,8 @@ static void digic_init(Object *obj)
|
|||
int i;
|
||||
|
||||
object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
|
||||
"arm946-" TYPE_ARM_CPU, &error_abort, NULL);
|
||||
ARM_CPU_TYPE_NAME("arm946"),
|
||||
&error_abort, NULL);
|
||||
|
||||
for (i = 0; i < DIGIC4_NB_TIMERS; i++) {
|
||||
#define DIGIC_TIMER_NAME_MLEN 11
|
||||
|
|
|
@ -131,8 +131,8 @@ exynos4_boards_init_common(MachineState *machine,
|
|||
exynos4_boards_init_ram(s, get_system_memory(),
|
||||
exynos4_board_ram_size[board_type]);
|
||||
|
||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_EXYNOS4210_SOC);
|
||||
qdev_set_parent_bus(DEVICE(&s->soc), sysbus_get_default());
|
||||
sysbus_init_child_obj(OBJECT(machine), "soc",
|
||||
&s->soc, sizeof(s->soc), TYPE_EXYNOS4210_SOC);
|
||||
object_property_set_bool(OBJECT(&s->soc), true, "realized",
|
||||
&error_fatal);
|
||||
|
||||
|
|
|
@ -36,7 +36,9 @@ static void fsl_imx25_init(Object *obj)
|
|||
FslIMX25State *s = FSL_IMX25(obj);
|
||||
int i;
|
||||
|
||||
object_initialize(&s->cpu, sizeof(s->cpu), "arm926-" TYPE_ARM_CPU);
|
||||
object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
|
||||
ARM_CPU_TYPE_NAME("arm926"),
|
||||
&error_abort, NULL);
|
||||
|
||||
sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic),
|
||||
TYPE_IMX_AVIC);
|
||||
|
|
|
@ -33,7 +33,9 @@ static void fsl_imx31_init(Object *obj)
|
|||
FslIMX31State *s = FSL_IMX31(obj);
|
||||
int i;
|
||||
|
||||
object_initialize(&s->cpu, sizeof(s->cpu), "arm1136-" TYPE_ARM_CPU);
|
||||
object_initialize_child(obj, "cpu", &s->cpu, sizeof(s->cpu),
|
||||
ARM_CPU_TYPE_NAME("arm1136"),
|
||||
&error_abort, NULL);
|
||||
|
||||
sysbus_init_child_obj(obj, "avic", &s->avic, sizeof(s->avic),
|
||||
TYPE_IMX_AVIC);
|
||||
|
|
|
@ -43,7 +43,8 @@ static void fsl_imx6_init(Object *obj)
|
|||
for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX6_NUM_CPUS); i++) {
|
||||
snprintf(name, NAME_SIZE, "cpu%d", i);
|
||||
object_initialize_child(obj, name, &s->cpu[i], sizeof(s->cpu[i]),
|
||||
"cortex-a9-" TYPE_ARM_CPU, &error_abort, NULL);
|
||||
ARM_CPU_TYPE_NAME("cortex-a9"),
|
||||
&error_abort, NULL);
|
||||
}
|
||||
|
||||
sysbus_init_child_obj(obj, "a9mpcore", &s->a9mpcore, sizeof(s->a9mpcore),
|
||||
|
|
|
@ -34,7 +34,7 @@ static void fsl_imx6ul_init(Object *obj)
|
|||
int i;
|
||||
|
||||
object_initialize_child(obj, "cpu0", &s->cpu, sizeof(s->cpu),
|
||||
"cortex-a7-" TYPE_ARM_CPU, &error_abort, NULL);
|
||||
ARM_CPU_TYPE_NAME("cortex-a7"), &error_abort, NULL);
|
||||
|
||||
/*
|
||||
* A7MPCORE
|
||||
|
|
|
@ -30,7 +30,6 @@ static void mcimx7d_sabre_init(MachineState *machine)
|
|||
{
|
||||
static struct arm_boot_info boot_info;
|
||||
MCIMX7Sabre *s = g_new0(MCIMX7Sabre, 1);
|
||||
Object *soc;
|
||||
int i;
|
||||
|
||||
if (machine->ram_size > FSL_IMX7_MMDC_SIZE) {
|
||||
|
@ -49,10 +48,10 @@ static void mcimx7d_sabre_init(MachineState *machine)
|
|||
.nb_cpus = machine->smp.cpus,
|
||||
};
|
||||
|
||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX7);
|
||||
soc = OBJECT(&s->soc);
|
||||
object_property_add_child(OBJECT(machine), "soc", soc, &error_fatal);
|
||||
object_property_set_bool(soc, true, "realized", &error_fatal);
|
||||
object_initialize_child(OBJECT(machine), "soc",
|
||||
&s->soc, sizeof(s->soc),
|
||||
TYPE_FSL_IMX7, &error_fatal, NULL);
|
||||
object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal);
|
||||
|
||||
memory_region_allocate_system_memory(&s->ram, NULL, "mcimx7d-sabre.ram",
|
||||
machine->ram_size);
|
||||
|
|
|
@ -427,10 +427,10 @@ static void mps2tz_common_init(MachineState *machine)
|
|||
/* The sec_resp_cfg output from the IoTKit must be split into multiple
|
||||
* lines, one for each of the PPCs we create here, plus one per MSC.
|
||||
*/
|
||||
object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
|
||||
TYPE_SPLIT_IRQ);
|
||||
object_property_add_child(OBJECT(machine), "sec-resp-splitter",
|
||||
OBJECT(&mms->sec_resp_splitter), &error_abort);
|
||||
object_initialize_child(OBJECT(machine), "sec-resp-splitter",
|
||||
&mms->sec_resp_splitter,
|
||||
sizeof(mms->sec_resp_splitter),
|
||||
TYPE_SPLIT_IRQ, &error_abort, NULL);
|
||||
object_property_set_int(OBJECT(&mms->sec_resp_splitter),
|
||||
ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc),
|
||||
"num-lines", &error_fatal);
|
||||
|
@ -465,10 +465,9 @@ static void mps2tz_common_init(MachineState *machine)
|
|||
* Tx, Rx and "combined" IRQs are sent to the NVIC separately.
|
||||
* Create the OR gate for this.
|
||||
*/
|
||||
object_initialize(&mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate),
|
||||
TYPE_OR_IRQ);
|
||||
object_property_add_child(OBJECT(mms), "uart-irq-orgate",
|
||||
OBJECT(&mms->uart_irq_orgate), &error_abort);
|
||||
object_initialize_child(OBJECT(mms), "uart-irq-orgate",
|
||||
&mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate),
|
||||
TYPE_OR_IRQ, &error_abort, NULL);
|
||||
object_property_set_int(OBJECT(&mms->uart_irq_orgate), 10, "num-lines",
|
||||
&error_fatal);
|
||||
object_property_set_bool(OBJECT(&mms->uart_irq_orgate), true,
|
||||
|
|
|
@ -424,10 +424,11 @@ static void musca_init(MachineState *machine)
|
|||
* The sec_resp_cfg output from the SSE-200 must be split into multiple
|
||||
* lines, one for each of the PPCs we create here.
|
||||
*/
|
||||
object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
|
||||
TYPE_SPLIT_IRQ);
|
||||
object_property_add_child(OBJECT(machine), "sec-resp-splitter",
|
||||
OBJECT(&mms->sec_resp_splitter), &error_fatal);
|
||||
object_initialize_child(OBJECT(machine), "sec-resp-splitter",
|
||||
&mms->sec_resp_splitter,
|
||||
sizeof(mms->sec_resp_splitter),
|
||||
TYPE_SPLIT_IRQ, &error_fatal, NULL);
|
||||
|
||||
object_property_set_int(OBJECT(&mms->sec_resp_splitter),
|
||||
ARRAY_SIZE(mms->ppc), "num-lines", &error_fatal);
|
||||
object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
|
||||
|
|
|
@ -381,6 +381,7 @@ typedef struct SMMUEventInfo {
|
|||
uint32_t sid;
|
||||
bool recorded;
|
||||
bool record_trans_faults;
|
||||
bool inval_ste_allowed;
|
||||
union {
|
||||
struct {
|
||||
uint32_t ssid;
|
||||
|
|
|
@ -320,6 +320,9 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
|
|||
uint32_t config;
|
||||
|
||||
if (!STE_VALID(ste)) {
|
||||
if (!event->inval_ste_allowed) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "invalid STE\n");
|
||||
}
|
||||
goto bad_ste;
|
||||
}
|
||||
|
||||
|
@ -406,8 +409,10 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
|
|||
|
||||
if (!span) {
|
||||
/* l2ptr is not valid */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"invalid sid=%d (L1STD span=0)\n", sid);
|
||||
if (!event->inval_ste_allowed) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"invalid sid=%d (L1STD span=0)\n", sid);
|
||||
}
|
||||
event->type = SMMU_EVT_C_BAD_STREAMID;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -602,7 +607,9 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
|
|||
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
|
||||
SMMUv3State *s = sdev->smmu;
|
||||
uint32_t sid = smmu_get_sid(sdev);
|
||||
SMMUEventInfo event = {.type = SMMU_EVT_NONE, .sid = sid};
|
||||
SMMUEventInfo event = {.type = SMMU_EVT_NONE,
|
||||
.sid = sid,
|
||||
.inval_ste_allowed = false};
|
||||
SMMUPTWEventInfo ptw_info = {};
|
||||
SMMUTranslationStatus status;
|
||||
SMMUState *bs = ARM_SMMU(s);
|
||||
|
@ -795,16 +802,13 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
|
|||
dma_addr_t iova)
|
||||
{
|
||||
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
|
||||
SMMUEventInfo event = {};
|
||||
SMMUEventInfo event = {.inval_ste_allowed = true};
|
||||
SMMUTransTableInfo *tt;
|
||||
SMMUTransCfg *cfg;
|
||||
IOMMUTLBEntry entry;
|
||||
|
||||
cfg = smmuv3_get_config(sdev, &event);
|
||||
if (!cfg) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s error decoding the configuration for iommu mr=%s\n",
|
||||
__func__, mr->parent_obj.name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -196,8 +196,8 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
|
|||
|
||||
object_initialize_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]",
|
||||
&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]),
|
||||
"cortex-r5f-" TYPE_ARM_CPU, &error_abort,
|
||||
NULL);
|
||||
ARM_CPU_TYPE_NAME("cortex-r5f"),
|
||||
&error_abort, NULL);
|
||||
|
||||
name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
|
||||
if (strcmp(name, boot_cpu)) {
|
||||
|
@ -237,8 +237,8 @@ static void xlnx_zynqmp_init(Object *obj)
|
|||
for (i = 0; i < num_apus; i++) {
|
||||
object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]",
|
||||
&s->apu_cpu[i], sizeof(s->apu_cpu[i]),
|
||||
"cortex-a53-" TYPE_ARM_CPU, &error_abort,
|
||||
NULL);
|
||||
ARM_CPU_TYPE_NAME("cortex-a53"),
|
||||
&error_abort, NULL);
|
||||
}
|
||||
|
||||
sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
|
||||
|
|
|
@ -566,14 +566,14 @@ static void xilinx_axidma_init(Object *obj)
|
|||
XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||
TYPE_XILINX_AXI_DMA_DATA_STREAM);
|
||||
object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
|
||||
TYPE_XILINX_AXI_DMA_CONTROL_STREAM);
|
||||
object_property_add_child(OBJECT(s), "axistream-connected-target",
|
||||
(Object *)&s->rx_data_dev, &error_abort);
|
||||
object_property_add_child(OBJECT(s), "axistream-control-connected-target",
|
||||
(Object *)&s->rx_control_dev, &error_abort);
|
||||
object_initialize_child(OBJECT(s), "axistream-connected-target",
|
||||
&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||
TYPE_XILINX_AXI_DMA_DATA_STREAM, &error_abort,
|
||||
NULL);
|
||||
object_initialize_child(OBJECT(s), "axistream-control-connected-target",
|
||||
&s->rx_control_dev, sizeof(s->rx_control_dev),
|
||||
TYPE_XILINX_AXI_DMA_CONTROL_STREAM, &error_abort,
|
||||
NULL);
|
||||
|
||||
sysbus_init_irq(sbd, &s->streams[0].irq);
|
||||
sysbus_init_irq(sbd, &s->streams[1].irq);
|
||||
|
|
|
@ -994,15 +994,14 @@ static void xilinx_enet_init(Object *obj)
|
|||
XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||
TYPE_XILINX_AXI_ENET_DATA_STREAM);
|
||||
object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev),
|
||||
TYPE_XILINX_AXI_ENET_CONTROL_STREAM);
|
||||
object_property_add_child(OBJECT(s), "axistream-connected-target",
|
||||
(Object *)&s->rx_data_dev, &error_abort);
|
||||
object_property_add_child(OBJECT(s), "axistream-control-connected-target",
|
||||
(Object *)&s->rx_control_dev, &error_abort);
|
||||
|
||||
object_initialize_child(OBJECT(s), "axistream-connected-target",
|
||||
&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||
TYPE_XILINX_AXI_ENET_DATA_STREAM, &error_abort,
|
||||
NULL);
|
||||
object_initialize_child(OBJECT(s), "axistream-control-connected-target",
|
||||
&s->rx_control_dev, sizeof(s->rx_control_dev),
|
||||
TYPE_XILINX_AXI_ENET_CONTROL_STREAM, &error_abort,
|
||||
NULL);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000);
|
||||
|
|
|
@ -44,6 +44,13 @@ enum timer_ctrl_op {
|
|||
op_pulse_enable
|
||||
};
|
||||
|
||||
/*
|
||||
* Minimum value of the reload register to filter out short period
|
||||
* timers which have a noticeable impact in emulation. 5us should be
|
||||
* enough, use 20us for "safety".
|
||||
*/
|
||||
#define TIMER_MIN_NS (20 * SCALE_US)
|
||||
|
||||
/**
|
||||
* Avoid mutual references between AspeedTimerCtrlState and AspeedTimer
|
||||
* structs, as it's a waste of memory. The ptimer BH callback needs to know
|
||||
|
@ -98,6 +105,14 @@ static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns)
|
|||
return t->reload - MIN(t->reload, ticks);
|
||||
}
|
||||
|
||||
static uint32_t calculate_min_ticks(AspeedTimer *t, uint32_t value)
|
||||
{
|
||||
uint32_t rate = calculate_rate(t);
|
||||
uint32_t min_ticks = muldiv64(TIMER_MIN_NS, rate, NANOSECONDS_PER_SECOND);
|
||||
|
||||
return value < min_ticks ? min_ticks : value;
|
||||
}
|
||||
|
||||
static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
|
||||
{
|
||||
uint64_t delta_ns;
|
||||
|
@ -261,7 +276,7 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
|
|||
switch (reg) {
|
||||
case TIMER_REG_RELOAD:
|
||||
old_reload = t->reload;
|
||||
t->reload = value;
|
||||
t->reload = calculate_min_ticks(t, value);
|
||||
|
||||
/* If the reload value was not previously set, or zero, and
|
||||
* the current value is valid, try to start the timer if it is
|
||||
|
|
|
@ -231,7 +231,7 @@ typedef struct CPUTLB { } CPUTLB;
|
|||
#endif /* !CONFIG_USER_ONLY && CONFIG_TCG */
|
||||
|
||||
/*
|
||||
* This structure must be placed in ArchCPU immedately
|
||||
* This structure must be placed in ArchCPU immediately
|
||||
* before CPUArchState, as a field named "neg".
|
||||
*/
|
||||
typedef struct CPUNegativeOffsetState {
|
||||
|
|
|
@ -1086,16 +1086,6 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
|
|||
*/
|
||||
void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
|
||||
|
||||
/**
|
||||
* memory_region_iommu_replay_all: replay existing IOMMU translations
|
||||
* to all the notifiers registered.
|
||||
*
|
||||
* Note: this is not related to record-and-replay functionality.
|
||||
*
|
||||
* @iommu_mr: the memory region to observe
|
||||
*/
|
||||
void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
|
||||
|
||||
/**
|
||||
* memory_region_unregister_iommu_notifier: unregister a notifier for
|
||||
* changes to IOMMU translation entries.
|
||||
|
|
|
@ -42,8 +42,6 @@ extern const char *keyboard_layout;
|
|||
extern int win2k_install_hack;
|
||||
extern int alt_grab;
|
||||
extern int ctrl_grab;
|
||||
extern int smp_cpus;
|
||||
extern unsigned int max_cpus;
|
||||
extern int cursor_hide;
|
||||
extern int graphic_rotate;
|
||||
extern int no_quit;
|
||||
|
|
9
memory.c
9
memory.c
|
@ -1922,15 +1922,6 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
|
|||
}
|
||||
}
|
||||
|
||||
void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr)
|
||||
{
|
||||
IOMMUNotifier *notifier;
|
||||
|
||||
IOMMU_NOTIFIER_FOREACH(notifier, iommu_mr) {
|
||||
memory_region_iommu_replay(iommu_mr, notifier);
|
||||
}
|
||||
}
|
||||
|
||||
void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
|
||||
IOMMUNotifier *n)
|
||||
{
|
||||
|
|
|
@ -2212,6 +2212,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
|
|||
* IO indicates that this register does I/O and therefore its accesses
|
||||
* need to be surrounded by gen_io_start()/gen_io_end(). In particular,
|
||||
* registers which implement clocks or timers require this.
|
||||
* RAISES_EXC is for when the read or write hook might raise an exception;
|
||||
* the generated code will synchronize the CPU state before calling the hook
|
||||
* so that it is safe for the hook to call raise_exception().
|
||||
*/
|
||||
#define ARM_CP_SPECIAL 0x0001
|
||||
#define ARM_CP_CONST 0x0002
|
||||
|
@ -2230,10 +2233,11 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
|
|||
#define ARM_CP_FPU 0x1000
|
||||
#define ARM_CP_SVE 0x2000
|
||||
#define ARM_CP_NO_GDB 0x4000
|
||||
#define ARM_CP_RAISES_EXC 0x8000
|
||||
/* Used only as a terminator for ARMCPRegInfo lists */
|
||||
#define ARM_CP_SENTINEL 0xffff
|
||||
/* Mask of only the flag bits in a type field */
|
||||
#define ARM_CP_FLAG_MASK 0x70ff
|
||||
#define ARM_CP_FLAG_MASK 0xf0ff
|
||||
|
||||
/* Valid values for ARMCPRegInfo state field, indicating which of
|
||||
* the AArch32 and AArch64 execution states this register is visible in.
|
||||
|
|
|
@ -2946,6 +2946,73 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
|
|||
ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs,
|
||||
&prot, &page_size, &fi, &cacheattrs);
|
||||
|
||||
if (ret) {
|
||||
/*
|
||||
* Some kinds of translation fault must cause exceptions rather
|
||||
* than being reported in the PAR.
|
||||
*/
|
||||
int current_el = arm_current_el(env);
|
||||
int target_el;
|
||||
uint32_t syn, fsr, fsc;
|
||||
bool take_exc = false;
|
||||
|
||||
if (fi.s1ptw && current_el == 1 && !arm_is_secure(env)
|
||||
&& (mmu_idx == ARMMMUIdx_S1NSE1 || mmu_idx == ARMMMUIdx_S1NSE0)) {
|
||||
/*
|
||||
* Synchronous stage 2 fault on an access made as part of the
|
||||
* translation table walk for AT S1E0* or AT S1E1* insn
|
||||
* executed from NS EL1. If this is a synchronous external abort
|
||||
* and SCR_EL3.EA == 1, then we take a synchronous external abort
|
||||
* to EL3. Otherwise the fault is taken as an exception to EL2,
|
||||
* and HPFAR_EL2 holds the faulting IPA.
|
||||
*/
|
||||
if (fi.type == ARMFault_SyncExternalOnWalk &&
|
||||
(env->cp15.scr_el3 & SCR_EA)) {
|
||||
target_el = 3;
|
||||
} else {
|
||||
env->cp15.hpfar_el2 = extract64(fi.s2addr, 12, 47) << 4;
|
||||
target_el = 2;
|
||||
}
|
||||
take_exc = true;
|
||||
} else if (fi.type == ARMFault_SyncExternalOnWalk) {
|
||||
/*
|
||||
* Synchronous external aborts during a translation table walk
|
||||
* are taken as Data Abort exceptions.
|
||||
*/
|
||||
if (fi.stage2) {
|
||||
if (current_el == 3) {
|
||||
target_el = 3;
|
||||
} else {
|
||||
target_el = 2;
|
||||
}
|
||||
} else {
|
||||
target_el = exception_target_el(env);
|
||||
}
|
||||
take_exc = true;
|
||||
}
|
||||
|
||||
if (take_exc) {
|
||||
/* Construct FSR and FSC using same logic as arm_deliver_fault() */
|
||||
if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
|
||||
arm_s1_regime_using_lpae_format(env, mmu_idx)) {
|
||||
fsr = arm_fi_to_lfsc(&fi);
|
||||
fsc = extract32(fsr, 0, 6);
|
||||
} else {
|
||||
fsr = arm_fi_to_sfsc(&fi);
|
||||
fsc = 0x3f;
|
||||
}
|
||||
/*
|
||||
* Report exception with ESR indicating a fault due to a
|
||||
* translation table walk for a cache maintenance instruction.
|
||||
*/
|
||||
syn = syn_data_abort_no_iss(current_el == target_el,
|
||||
fi.ea, 1, fi.s1ptw, 1, fsc);
|
||||
env->exception.vaddress = value;
|
||||
env->exception.fsr = fsr;
|
||||
raise_exception(env, EXCP_DATA_ABORT, syn, target_el);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_a64(env)) {
|
||||
format64 = true;
|
||||
} else if (arm_feature(env, ARM_FEATURE_LPAE)) {
|
||||
|
@ -3150,7 +3217,7 @@ static const ARMCPRegInfo vapa_cp_reginfo[] = {
|
|||
/* This underdecoding is safe because the reginfo is NO_RAW. */
|
||||
{ .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY,
|
||||
.access = PL1_W, .accessfn = ats_access,
|
||||
.writefn = ats_write, .type = ARM_CP_NO_RAW },
|
||||
.writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
|
||||
#endif
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
@ -4283,35 +4350,45 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
|
|||
/* 64 bit address translation operations */
|
||||
{ .name = "AT_S1E1R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S12E1W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 5,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S12E0R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 6,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S12E0W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 7,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
/* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present */
|
||||
{ .name = "AT_S1E3R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 0,
|
||||
.access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S1E3W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "PAR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_ALIAS,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0,
|
||||
|
@ -4893,11 +4970,11 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
|
|||
{ .name = "AT_S1E2R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0,
|
||||
.access = PL2_W, .accessfn = at_s1e2_access,
|
||||
.type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 },
|
||||
{ .name = "AT_S1E2W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL2_W, .accessfn = at_s1e2_access,
|
||||
.type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, .writefn = ats_write64 },
|
||||
/* The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE
|
||||
* if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3
|
||||
* with SCR.NS == 0 outside Monitor mode is UNPREDICTABLE; we choose
|
||||
|
@ -4905,10 +4982,10 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
|
|||
*/
|
||||
{ .name = "ATS1HR", .cp = 15, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0,
|
||||
.access = PL2_W,
|
||||
.writefn = ats1h_write, .type = ARM_CP_NO_RAW },
|
||||
.writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
|
||||
{ .name = "ATS1HW", .cp = 15, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL2_W,
|
||||
.writefn = ats1h_write, .type = ARM_CP_NO_RAW },
|
||||
.writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
|
||||
{ .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0,
|
||||
/* ARMv7 requires bit 0 and 1 to reset to 1. ARMv8 defines the
|
||||
|
|
|
@ -338,6 +338,13 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
|
|||
}
|
||||
}
|
||||
|
||||
void unallocated_encoding(DisasContext *s)
|
||||
{
|
||||
/* Unallocated and reserved encodings are uncategorized */
|
||||
gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(),
|
||||
default_exception_el(s));
|
||||
}
|
||||
|
||||
static void init_tmp_a64_array(DisasContext *s)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
|
@ -1707,6 +1714,12 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
|||
tcg_temp_free_ptr(tmpptr);
|
||||
tcg_temp_free_i32(tcg_syn);
|
||||
tcg_temp_free_i32(tcg_isread);
|
||||
} else if (ri->type & ARM_CP_RAISES_EXC) {
|
||||
/*
|
||||
* The readfn or writefn might raise an exception;
|
||||
* synchronize the CPU state in case it does.
|
||||
*/
|
||||
gen_a64_set_pc_im(s->pc_curr);
|
||||
}
|
||||
|
||||
/* Handle special cases first */
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#ifndef TARGET_ARM_TRANSLATE_A64_H
|
||||
#define TARGET_ARM_TRANSLATE_A64_H
|
||||
|
||||
void unallocated_encoding(DisasContext *s);
|
||||
|
||||
#define unsupported_encoding(s, insn) \
|
||||
do { \
|
||||
qemu_log_mask(LOG_UNIMP, \
|
||||
|
|
|
@ -880,8 +880,10 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
|
|||
/* gpreg to fpreg */
|
||||
tmp = load_reg(s, a->rt);
|
||||
neon_store_reg32(tmp, a->vm);
|
||||
tcg_temp_free_i32(tmp);
|
||||
tmp = load_reg(s, a->rt2);
|
||||
neon_store_reg32(tmp, a->vm + 1);
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -915,10 +915,27 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
|
|||
store_cpu_field(var, thumb);
|
||||
}
|
||||
|
||||
/* Set PC and Thumb state from var. var is marked as dead.
|
||||
/*
|
||||
* Set PC and Thumb state from var. var is marked as dead.
|
||||
* For M-profile CPUs, include logic to detect exception-return
|
||||
* branches and handle them. This is needed for Thumb POP/LDM to PC, LDR to PC,
|
||||
* and BX reg, and no others, and happens only for code in Handler mode.
|
||||
* The Security Extension also requires us to check for the FNC_RETURN
|
||||
* which signals a function return from non-secure state; this can happen
|
||||
* in both Handler and Thread mode.
|
||||
* To avoid having to do multiple comparisons in inline generated code,
|
||||
* we make the check we do here loose, so it will match for EXC_RETURN
|
||||
* in Thread mode. For system emulation do_v7m_exception_exit() checks
|
||||
* for these spurious cases and returns without doing anything (giving
|
||||
* the same behaviour as for a branch to a non-magic address).
|
||||
*
|
||||
* In linux-user mode it is unclear what the right behaviour for an
|
||||
* attempted FNC_RETURN should be, because in real hardware this will go
|
||||
* directly to Secure code (ie not the Linux kernel) which will then treat
|
||||
* the error in any way it chooses. For QEMU we opt to make the FNC_RETURN
|
||||
* attempt behave the way it would on a CPU without the security extension,
|
||||
* which is to say "like a normal branch". That means we can simply treat
|
||||
* all branches as normal with no magic address behaviour.
|
||||
*/
|
||||
static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
|
||||
{
|
||||
|
@ -926,10 +943,12 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
|
|||
* s->base.is_jmp that we need to do the rest of the work later.
|
||||
*/
|
||||
gen_bx(s, var);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY) ||
|
||||
(s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M))) {
|
||||
s->base.is_jmp = DISAS_BX_EXCRET;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void gen_bx_excret_final_code(DisasContext *s)
|
||||
|
@ -1231,7 +1250,7 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
|
|||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
void unallocated_encoding(DisasContext *s)
|
||||
static void unallocated_encoding(DisasContext *s)
|
||||
{
|
||||
/* Unallocated and reserved encodings are uncategorized */
|
||||
gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(),
|
||||
|
@ -7191,6 +7210,13 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_ptr(tmpptr);
|
||||
tcg_temp_free_i32(tcg_syn);
|
||||
tcg_temp_free_i32(tcg_isread);
|
||||
} else if (ri->type & ARM_CP_RAISES_EXC) {
|
||||
/*
|
||||
* The readfn or writefn might raise an exception;
|
||||
* synchronize the CPU state in case it does.
|
||||
*/
|
||||
gen_set_condexec(s);
|
||||
gen_set_pc_im(s, s->pc_curr);
|
||||
}
|
||||
|
||||
/* Handle special cases first */
|
||||
|
@ -8824,7 +8850,16 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|||
if (rd != 15) {
|
||||
tmp3 = load_reg(s, rd);
|
||||
if (insn & (1 << 6)) {
|
||||
tcg_gen_sub_i32(tmp, tmp, tmp3);
|
||||
/*
|
||||
* For SMMLS, we need a 64-bit subtract.
|
||||
* Borrow caused by a non-zero multiplicand
|
||||
* lowpart, and the correct result lowpart
|
||||
* for rounding.
|
||||
*/
|
||||
TCGv_i32 zero = tcg_const_i32(0);
|
||||
tcg_gen_sub2_i32(tmp2, tmp, zero, tmp3,
|
||||
tmp2, tmp);
|
||||
tcg_temp_free_i32(zero);
|
||||
} else {
|
||||
tcg_gen_add_i32(tmp, tmp, tmp3);
|
||||
}
|
||||
|
@ -10068,7 +10103,14 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
|||
if (insn & (1 << 20)) {
|
||||
tcg_gen_add_i32(tmp, tmp, tmp3);
|
||||
} else {
|
||||
tcg_gen_sub_i32(tmp, tmp, tmp3);
|
||||
/*
|
||||
* For SMMLS, we need a 64-bit subtract.
|
||||
* Borrow caused by a non-zero multiplicand lowpart,
|
||||
* and the correct result lowpart for rounding.
|
||||
*/
|
||||
TCGv_i32 zero = tcg_const_i32(0);
|
||||
tcg_gen_sub2_i32(tmp2, tmp, zero, tmp3, tmp2, tmp);
|
||||
tcg_temp_free_i32(zero);
|
||||
}
|
||||
tcg_temp_free_i32(tmp3);
|
||||
}
|
||||
|
|
|
@ -99,8 +99,6 @@ typedef struct DisasCompare {
|
|||
bool value_global;
|
||||
} DisasCompare;
|
||||
|
||||
void unallocated_encoding(DisasContext *s);
|
||||
|
||||
/* Share the TCG temporaries common between 32 and 64 bit modes. */
|
||||
extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
|
||||
extern TCGv_i64 cpu_exclusive_addr;
|
||||
|
|
|
@ -101,7 +101,7 @@ This can be overridden using the following function modifiers:
|
|||
canonical locations before calling the helper.
|
||||
- TCG_CALL_NO_WRITE_GLOBALS means that the helper does not modify any globals.
|
||||
They will only be saved to their canonical location before calling helpers,
|
||||
but they won't be reloaded afterwise.
|
||||
but they won't be reloaded afterwards.
|
||||
- TCG_CALL_NO_SIDE_EFFECTS means that the call to the function is removed if
|
||||
the return value is not used.
|
||||
|
||||
|
|
Loading…
Reference in a new issue