mirror of https://github.com/xemu-project/xemu.git
target-arm queue:
* more preparatory work for v8M support * convert some omap devices away from old_mmio * remove out of date ARM ARM section references in comments * add the Smartfusion2 board -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJZw+uIAAoJEDwlJe0UNgzeLFsP/juEvIdvd+PrjSmFgxuz0g26 dph1nMuQIpYaS/rb00Rr69SQTPPX0P/Qg8QFE57QmAl76l/3ZzvHC6qKk6hLSr0F MjoWTdWNKnTVgLVd00DAXdGdeHYPaq6tBAVjDvjiZss7Vx+V0fzf7QND1dOPKdfZ pOQPQPK5L55QwlMmh/fg+fWQqmIZT/F3M9hhoLtRYnCQklkwM6V0AArHF2vObosO oJvR7sVi10H336PkiGPNaRahNyb0Mnq8xem3vyGPLwn0rSStK8QApfCB2VZXKOCC E6afahI6+pkI2n9fMIyI8NxTey3E/ptWHUpUO//0fTUGv0TM2cUu5CPh3t0MamfQ jHTiXXVD6+PfzNOJ5bLJ7qMzv+rG9woABWdRw5v62mkE8/KmcVIX2bcsl+OnzBE7 t4Lj3oKdMtOYObK3UEFmvjcS6Km9Iv5L61Vc/b/MH/9ixxkvc+ovs8tPun344a7+ 0JTDX6BBszFHU+lKNGk1q+0wbh5pYi27lcfTCRIxvHokwdz22qnLHqKRfDRfm2vx qxhyyxrBDnUU5PhBxMapBIg0WPSAHgAxC2owBIxULlPW11c//tYW01g7M3ugG3tx rDCKL0vK7EmOVIi4uD1IMUkJkMLoBjbeJ7x5iRdophsXWoCG+R33iUhlonQZft0v p/mzbQZWKOaCKYzs6a0Y =5t7E -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170921' into staging target-arm queue: * more preparatory work for v8M support * convert some omap devices away from old_mmio * remove out of date ARM ARM section references in comments * add the Smartfusion2 board # gpg: Signature made Thu 21 Sep 2017 17:40:40 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20170921: (31 commits) msf2: Add Emcraft's Smartfusion2 SOM kit msf2: Add Smartfusion2 SoC msf2: Add Smartfusion2 SPI controller msf2: Microsemi Smartfusion2 System Register block msf2: Add Smartfusion2 System timer hw/arm/omap2.c: Don't use old_mmio hw/i2c/omap_i2c.c: Don't use old_mmio hw/timer/omap_gptimer: Don't use old_mmio hw/timer/omap_synctimer.c: Don't use old_mmio hw/gpio/omap_gpio.c: Don't use old_mmio hw/arm/palm.c: Don't use old_mmio for static_ops target/arm: Remove out of date ARM ARM section references in A64 decoder nvic: Support banked exceptions in acknowledge and complete nvic: Make SHCSR banked for v8M nvic: Make ICSR banked for v8M target/arm: Handle banking in negative-execution-priority check in cpu_mmu_index() nvic: Handle v8M changes in nvic_exec_prio() nvic: Disable the non-secure HardFault if AIRCR.BFHFNMINS is clear nvic: Implement v8M changes to fixed priority exceptions nvic: In escalation to HardFault, support HF not being priority -1 ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0a8066f0c0
|
@ -129,3 +129,4 @@ CONFIG_ACPI=y
|
|||
CONFIG_SMBIOS=y
|
||||
CONFIG_ASPEED_SOC=y
|
||||
CONFIG_GPIO_KEY=y
|
||||
CONFIG_MSF2=y
|
||||
|
|
|
@ -19,3 +19,4 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
|
|||
obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
|
||||
obj-$(CONFIG_MPS2) += mps2.o
|
||||
obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* SmartFusion2 SoC emulation.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* 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 "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "hw/arm/msf2-soc.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
|
||||
#define MSF2_TIMER_BASE 0x40004000
|
||||
#define MSF2_SYSREG_BASE 0x40038000
|
||||
|
||||
#define ENVM_BASE_ADDRESS 0x60000000
|
||||
|
||||
#define SRAM_BASE_ADDRESS 0x20000000
|
||||
|
||||
#define MSF2_ENVM_MAX_SIZE (512 * K_BYTE)
|
||||
|
||||
/*
|
||||
* eSRAM max size is 80k without SECDED(Single error correction and
|
||||
* dual error detection) feature and 64k with SECDED.
|
||||
* We do not support SECDED now.
|
||||
*/
|
||||
#define MSF2_ESRAM_MAX_SIZE (80 * K_BYTE)
|
||||
|
||||
static const uint32_t spi_addr[MSF2_NUM_SPIS] = { 0x40001000 , 0x40011000 };
|
||||
static const uint32_t uart_addr[MSF2_NUM_UARTS] = { 0x40000000 , 0x40010000 };
|
||||
|
||||
static const int spi_irq[MSF2_NUM_SPIS] = { 2, 3 };
|
||||
static const int uart_irq[MSF2_NUM_UARTS] = { 10, 11 };
|
||||
static const int timer_irq[MSF2_NUM_TIMERS] = { 14, 15 };
|
||||
|
||||
static void m2sxxx_soc_initfn(Object *obj)
|
||||
{
|
||||
MSF2State *s = MSF2_SOC(obj);
|
||||
int i;
|
||||
|
||||
object_initialize(&s->armv7m, sizeof(s->armv7m), TYPE_ARMV7M);
|
||||
qdev_set_parent_bus(DEVICE(&s->armv7m), sysbus_get_default());
|
||||
|
||||
object_initialize(&s->sysreg, sizeof(s->sysreg), TYPE_MSF2_SYSREG);
|
||||
qdev_set_parent_bus(DEVICE(&s->sysreg), sysbus_get_default());
|
||||
|
||||
object_initialize(&s->timer, sizeof(s->timer), TYPE_MSS_TIMER);
|
||||
qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default());
|
||||
|
||||
for (i = 0; i < MSF2_NUM_SPIS; i++) {
|
||||
object_initialize(&s->spi[i], sizeof(s->spi[i]),
|
||||
TYPE_MSS_SPI);
|
||||
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
|
||||
}
|
||||
}
|
||||
|
||||
static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
{
|
||||
MSF2State *s = MSF2_SOC(dev_soc);
|
||||
DeviceState *dev, *armv7m;
|
||||
SysBusDevice *busdev;
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
MemoryRegion *nvm = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *nvm_alias = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||
|
||||
memory_region_init_rom(nvm, NULL, "MSF2.eNVM", s->envm_size,
|
||||
&error_fatal);
|
||||
/*
|
||||
* On power-on, the eNVM region 0x60000000 is automatically
|
||||
* remapped to the Cortex-M3 processor executable region
|
||||
* start address (0x0). We do not support remapping other eNVM,
|
||||
* eSRAM and DDR regions by guest(via Sysreg) currently.
|
||||
*/
|
||||
memory_region_init_alias(nvm_alias, NULL, "MSF2.eNVM",
|
||||
nvm, 0, s->envm_size);
|
||||
|
||||
memory_region_add_subregion(system_memory, ENVM_BASE_ADDRESS, nvm);
|
||||
memory_region_add_subregion(system_memory, 0, nvm_alias);
|
||||
|
||||
memory_region_init_ram(sram, NULL, "MSF2.eSRAM", s->esram_size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
|
||||
|
||||
armv7m = DEVICE(&s->armv7m);
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 81);
|
||||
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
|
||||
object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()),
|
||||
"memory", &error_abort);
|
||||
object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->m3clk) {
|
||||
error_setg(errp, "Invalid m3clk value");
|
||||
error_append_hint(errp, "m3clk can not be zero\n");
|
||||
return;
|
||||
}
|
||||
system_clock_scale = NANOSECONDS_PER_SECOND / s->m3clk;
|
||||
|
||||
for (i = 0; i < MSF2_NUM_UARTS; i++) {
|
||||
if (serial_hds[i]) {
|
||||
serial_mm_init(get_system_memory(), uart_addr[i], 2,
|
||||
qdev_get_gpio_in(armv7m, uart_irq[i]),
|
||||
115200, serial_hds[i], DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
}
|
||||
|
||||
dev = DEVICE(&s->timer);
|
||||
/* APB0 clock is the timer input clock */
|
||||
qdev_prop_set_uint32(dev, "clock-frequency", s->m3clk / s->apb0div);
|
||||
object_property_set_bool(OBJECT(&s->timer), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, MSF2_TIMER_BASE);
|
||||
sysbus_connect_irq(busdev, 0,
|
||||
qdev_get_gpio_in(armv7m, timer_irq[0]));
|
||||
sysbus_connect_irq(busdev, 1,
|
||||
qdev_get_gpio_in(armv7m, timer_irq[1]));
|
||||
|
||||
dev = DEVICE(&s->sysreg);
|
||||
qdev_prop_set_uint32(dev, "apb0divisor", s->apb0div);
|
||||
qdev_prop_set_uint32(dev, "apb1divisor", s->apb1div);
|
||||
object_property_set_bool(OBJECT(&s->sysreg), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, MSF2_SYSREG_BASE);
|
||||
|
||||
for (i = 0; i < MSF2_NUM_SPIS; i++) {
|
||||
gchar *bus_name;
|
||||
|
||||
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
|
||||
qdev_get_gpio_in(armv7m, spi_irq[i]));
|
||||
|
||||
/* Alias controller SPI bus to the SoC itself */
|
||||
bus_name = g_strdup_printf("spi%d", i);
|
||||
object_property_add_alias(OBJECT(s), bus_name,
|
||||
OBJECT(&s->spi[i]), "spi",
|
||||
&error_abort);
|
||||
g_free(bus_name);
|
||||
}
|
||||
|
||||
/* Below devices are not modelled yet. */
|
||||
create_unimplemented_device("i2c_0", 0x40002000, 0x1000);
|
||||
create_unimplemented_device("dma", 0x40003000, 0x1000);
|
||||
create_unimplemented_device("watchdog", 0x40005000, 0x1000);
|
||||
create_unimplemented_device("i2c_1", 0x40012000, 0x1000);
|
||||
create_unimplemented_device("gpio", 0x40013000, 0x1000);
|
||||
create_unimplemented_device("hs-dma", 0x40014000, 0x1000);
|
||||
create_unimplemented_device("can", 0x40015000, 0x1000);
|
||||
create_unimplemented_device("rtc", 0x40017000, 0x1000);
|
||||
create_unimplemented_device("apb_config", 0x40020000, 0x10000);
|
||||
create_unimplemented_device("emac", 0x40041000, 0x1000);
|
||||
create_unimplemented_device("usb", 0x40043000, 0x1000);
|
||||
}
|
||||
|
||||
static Property m2sxxx_soc_properties[] = {
|
||||
/*
|
||||
* part name specifies the type of SmartFusion2 device variant(this
|
||||
* property is for information purpose only.
|
||||
*/
|
||||
DEFINE_PROP_STRING("cpu-type", MSF2State, cpu_type),
|
||||
DEFINE_PROP_STRING("part-name", MSF2State, part_name),
|
||||
DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE),
|
||||
DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size,
|
||||
MSF2_ESRAM_MAX_SIZE),
|
||||
/* Libero GUI shows 100Mhz as default for clocks */
|
||||
DEFINE_PROP_UINT32("m3clk", MSF2State, m3clk, 100 * 1000000),
|
||||
/* default divisors in Libero GUI */
|
||||
DEFINE_PROP_UINT8("apb0div", MSF2State, apb0div, 2),
|
||||
DEFINE_PROP_UINT8("apb1div", MSF2State, apb1div, 2),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void m2sxxx_soc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = m2sxxx_soc_realize;
|
||||
dc->props = m2sxxx_soc_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo m2sxxx_soc_info = {
|
||||
.name = TYPE_MSF2_SOC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MSF2State),
|
||||
.instance_init = m2sxxx_soc_initfn,
|
||||
.class_init = m2sxxx_soc_class_init,
|
||||
};
|
||||
|
||||
static void m2sxxx_soc_types(void)
|
||||
{
|
||||
type_register_static(&m2sxxx_soc_info);
|
||||
}
|
||||
|
||||
type_init(m2sxxx_soc_types)
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* SmartFusion2 SOM starter kit(from Emcraft) emulation.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* 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 "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "hw/arm/msf2-soc.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define DDR_BASE_ADDRESS 0xA0000000
|
||||
#define DDR_SIZE (64 * M_BYTE)
|
||||
|
||||
#define M2S010_ENVM_SIZE (256 * K_BYTE)
|
||||
#define M2S010_ESRAM_SIZE (64 * K_BYTE)
|
||||
|
||||
static void emcraft_sf2_s2s010_init(MachineState *machine)
|
||||
{
|
||||
DeviceState *dev;
|
||||
DeviceState *spi_flash;
|
||||
MSF2State *soc;
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
qemu_irq cs_line;
|
||||
SSIBus *spi_bus;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ddr = g_new(MemoryRegion, 1);
|
||||
|
||||
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
|
||||
error_report("This board can only be used with CPU %s",
|
||||
mc->default_cpu_type);
|
||||
}
|
||||
|
||||
memory_region_init_ram(ddr, NULL, "ddr-ram", DDR_SIZE,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(sysmem, DDR_BASE_ADDRESS, ddr);
|
||||
|
||||
dev = qdev_create(NULL, TYPE_MSF2_SOC);
|
||||
qdev_prop_set_string(dev, "part-name", "M2S010");
|
||||
qdev_prop_set_string(dev, "cpu-type", mc->default_cpu_type);
|
||||
|
||||
qdev_prop_set_uint64(dev, "eNVM-size", M2S010_ENVM_SIZE);
|
||||
qdev_prop_set_uint64(dev, "eSRAM-size", M2S010_ESRAM_SIZE);
|
||||
|
||||
/*
|
||||
* CPU clock and peripheral clocks(APB0, APB1)are configurable
|
||||
* in Libero. CPU clock is divided by APB0 and APB1 divisors for
|
||||
* peripherals. Emcraft's SoM kit comes with these settings by default.
|
||||
*/
|
||||
qdev_prop_set_uint32(dev, "m3clk", 142 * 1000000);
|
||||
qdev_prop_set_uint32(dev, "apb0div", 2);
|
||||
qdev_prop_set_uint32(dev, "apb1div", 2);
|
||||
|
||||
object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal);
|
||||
|
||||
soc = MSF2_SOC(dev);
|
||||
|
||||
/* Attach SPI flash to SPI0 controller */
|
||||
spi_bus = (SSIBus *)qdev_get_child_bus(dev, "spi0");
|
||||
spi_flash = ssi_create_slave_no_init(spi_bus, "s25sl12801");
|
||||
qdev_prop_set_uint8(spi_flash, "spansion-cr2nv", 1);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(spi_flash, "drive", blk_by_legacy_dinfo(dinfo),
|
||||
&error_fatal);
|
||||
}
|
||||
qdev_init_nofail(spi_flash);
|
||||
cs_line = qdev_get_gpio_in_named(spi_flash, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&soc->spi[0]), 1, cs_line);
|
||||
|
||||
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
|
||||
soc->envm_size);
|
||||
}
|
||||
|
||||
static void emcraft_sf2_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "SmartFusion2 SOM kit from Emcraft (M2S010)";
|
||||
mc->init = emcraft_sf2_s2s010_init;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("emcraft-sf2", emcraft_sf2_machine_init)
|
|
@ -2087,19 +2087,44 @@ static void omap_sysctl_write(void *opaque, hwaddr addr,
|
|||
}
|
||||
}
|
||||
|
||||
static uint64_t omap_sysctl_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return omap_sysctl_read8(opaque, addr);
|
||||
case 2:
|
||||
return omap_badwidth_read32(opaque, addr); /* TODO */
|
||||
case 4:
|
||||
return omap_sysctl_read(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_sysctl_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
omap_sysctl_write8(opaque, addr, value);
|
||||
break;
|
||||
case 2:
|
||||
omap_badwidth_write32(opaque, addr, value); /* TODO */
|
||||
break;
|
||||
case 4:
|
||||
omap_sysctl_write(opaque, addr, value);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_sysctl_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap_sysctl_read8,
|
||||
omap_badwidth_read32, /* TODO */
|
||||
omap_sysctl_read,
|
||||
},
|
||||
.write = {
|
||||
omap_sysctl_write8,
|
||||
omap_badwidth_write32, /* TODO */
|
||||
omap_sysctl_write,
|
||||
},
|
||||
},
|
||||
.read = omap_sysctl_readfn,
|
||||
.write = omap_sysctl_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
|
|
@ -31,26 +31,16 @@
|
|||
#include "exec/address-spaces.h"
|
||||
#include "cpu.h"
|
||||
|
||||
static uint32_t static_readb(void *opaque, hwaddr offset)
|
||||
static uint64_t static_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint32_t *val = (uint32_t *) opaque;
|
||||
return *val >> ((offset & 3) << 3);
|
||||
uint32_t *val = (uint32_t *)opaque;
|
||||
uint32_t sizemask = 7 >> size;
|
||||
|
||||
return *val >> ((offset & sizemask) << 3);
|
||||
}
|
||||
|
||||
static uint32_t static_readh(void *opaque, hwaddr offset)
|
||||
{
|
||||
uint32_t *val = (uint32_t *) opaque;
|
||||
return *val >> ((offset & 1) << 3);
|
||||
}
|
||||
|
||||
static uint32_t static_readw(void *opaque, hwaddr offset)
|
||||
{
|
||||
uint32_t *val = (uint32_t *) opaque;
|
||||
return *val >> ((offset & 0) << 3);
|
||||
}
|
||||
|
||||
static void static_write(void *opaque, hwaddr offset,
|
||||
uint32_t value)
|
||||
static void static_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
#ifdef SPY
|
||||
printf("%s: value %08lx written at " PA_FMT "\n",
|
||||
|
@ -59,10 +49,10 @@ static void static_write(void *opaque, hwaddr offset,
|
|||
}
|
||||
|
||||
static const MemoryRegionOps static_ops = {
|
||||
.old_mmio = {
|
||||
.read = { static_readb, static_readh, static_readw, },
|
||||
.write = { static_write, static_write, static_write, },
|
||||
},
|
||||
.read = static_read,
|
||||
.write = static_write,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
|
|
@ -525,17 +525,23 @@ static void omap2_gpio_module_write(void *opaque, hwaddr addr,
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t omap2_gpio_module_readp(void *opaque, hwaddr addr)
|
||||
static uint64_t omap2_gpio_module_readp(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
|
||||
}
|
||||
|
||||
static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
uint32_t cur = 0;
|
||||
uint32_t mask = 0xffff;
|
||||
|
||||
if (size == 4) {
|
||||
omap2_gpio_module_write(opaque, addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr & ~3) {
|
||||
case 0x00: /* GPIO_REVISION */
|
||||
case 0x14: /* GPIO_SYSSTATUS */
|
||||
|
@ -581,18 +587,10 @@ static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
|
|||
}
|
||||
|
||||
static const MemoryRegionOps omap2_gpio_module_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap2_gpio_module_readp,
|
||||
omap2_gpio_module_readp,
|
||||
omap2_gpio_module_read,
|
||||
},
|
||||
.write = {
|
||||
omap2_gpio_module_writep,
|
||||
omap2_gpio_module_writep,
|
||||
omap2_gpio_module_write,
|
||||
},
|
||||
},
|
||||
.read = omap2_gpio_module_readp,
|
||||
.write = omap2_gpio_module_writep,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
|
|
@ -430,19 +430,39 @@ static void omap_i2c_writeb(void *opaque, hwaddr addr,
|
|||
}
|
||||
}
|
||||
|
||||
static uint64_t omap_i2c_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 2:
|
||||
return omap_i2c_read(opaque, addr);
|
||||
default:
|
||||
return omap_badwidth_read16(opaque, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_i2c_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
/* Only the last fifo write can be 8 bit. */
|
||||
omap_i2c_writeb(opaque, addr, value);
|
||||
break;
|
||||
case 2:
|
||||
omap_i2c_write(opaque, addr, value);
|
||||
break;
|
||||
default:
|
||||
omap_badwidth_write16(opaque, addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_i2c_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap_badwidth_read16,
|
||||
omap_i2c_read,
|
||||
omap_badwidth_read16,
|
||||
},
|
||||
.write = {
|
||||
omap_i2c_writeb, /* Only the last fifo write can be 8 bit. */
|
||||
omap_i2c_write,
|
||||
omap_badwidth_write16,
|
||||
},
|
||||
},
|
||||
.read = omap_i2c_readfn,
|
||||
.write = omap_i2c_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -167,16 +167,17 @@ gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor 0x%x
|
|||
gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor 0x%x pending SGI %d"
|
||||
|
||||
# hw/intc/armv7m_nvic.c
|
||||
nvic_recompute_state(int vectpending, int exception_prio) "NVIC state recomputed: vectpending %d exception_prio %d"
|
||||
nvic_set_prio(int irq, uint8_t prio) "NVIC set irq %d priority %d"
|
||||
nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d"
|
||||
nvic_recompute_state_secure(int vectpending, bool vectpending_is_s_banked, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d is_s_banked %d vectpending_prio %d exception_prio %d"
|
||||
nvic_set_prio(int irq, bool secure, uint8_t prio) "NVIC set irq %d secure-bank %d priority %d"
|
||||
nvic_irq_update(int vectpending, int pendprio, int exception_prio, int level) "NVIC vectpending %d pending prio %d exception_prio %d: setting irq line to %d"
|
||||
nvic_escalate_prio(int irq, int irqprio, int runprio) "NVIC escalating irq %d to HardFault: insufficient priority %d >= %d"
|
||||
nvic_escalate_disabled(int irq) "NVIC escalating irq %d to HardFault: disabled"
|
||||
nvic_set_pending(int irq, int en, int prio) "NVIC set pending irq %d (enabled: %d priority %d)"
|
||||
nvic_clear_pending(int irq, int en, int prio) "NVIC clear pending irq %d (enabled: %d priority %d)"
|
||||
nvic_set_pending(int irq, bool secure, int en, int prio) "NVIC set pending irq %d secure-bank %d (enabled: %d priority %d)"
|
||||
nvic_clear_pending(int irq, bool secure, int en, int prio) "NVIC clear pending irq %d secure-bank %d (enabled: %d priority %d)"
|
||||
nvic_set_pending_level(int irq) "NVIC set pending: irq %d higher prio than vectpending: setting irq line to 1"
|
||||
nvic_acknowledge_irq(int irq, int prio) "NVIC acknowledge IRQ: %d now active (prio %d)"
|
||||
nvic_complete_irq(int irq) "NVIC complete IRQ %d"
|
||||
nvic_acknowledge_irq(int irq, int prio, bool targets_secure) "NVIC acknowledge IRQ: %d now active (prio %d targets_secure %d)"
|
||||
nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)"
|
||||
nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d"
|
||||
nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
|
||||
nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
|
||||
|
|
|
@ -59,3 +59,4 @@ obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
|
|||
obj-$(CONFIG_AUX) += auxbus.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
|
||||
obj-y += mmio_interface.o
|
||||
obj-$(CONFIG_MSF2) += msf2-sysreg.o
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* System Register block model of Microsemi SmartFusion2.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/misc/msf2-sysreg.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "trace.h"
|
||||
|
||||
static inline int msf2_divbits(uint32_t div)
|
||||
{
|
||||
int r = ctz32(div);
|
||||
|
||||
return (div < 8) ? r : r + 1;
|
||||
}
|
||||
|
||||
static void msf2_sysreg_reset(DeviceState *d)
|
||||
{
|
||||
MSF2SysregState *s = MSF2_SYSREG(d);
|
||||
|
||||
s->regs[MSSDDR_PLL_STATUS_LOW_CR] = 0x021A2358;
|
||||
s->regs[MSSDDR_PLL_STATUS] = 0x3;
|
||||
s->regs[MSSDDR_FACC1_CR] = msf2_divbits(s->apb0div) << 5 |
|
||||
msf2_divbits(s->apb1div) << 2;
|
||||
}
|
||||
|
||||
static uint64_t msf2_sysreg_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
MSF2SysregState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
offset >>= 2;
|
||||
if (offset < ARRAY_SIZE(s->regs)) {
|
||||
ret = s->regs[offset];
|
||||
trace_msf2_sysreg_read(offset << 2, ret);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%08" HWADDR_PRIx "\n", __func__,
|
||||
offset << 2);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void msf2_sysreg_write(void *opaque, hwaddr offset,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
MSF2SysregState *s = opaque;
|
||||
uint32_t newval = val;
|
||||
|
||||
offset >>= 2;
|
||||
|
||||
switch (offset) {
|
||||
case MSSDDR_PLL_STATUS:
|
||||
trace_msf2_sysreg_write_pll_status();
|
||||
break;
|
||||
|
||||
case ESRAM_CR:
|
||||
case DDR_CR:
|
||||
case ENVM_REMAP_BASE_CR:
|
||||
if (newval != s->regs[offset]) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
TYPE_MSF2_SYSREG": remapping not supported\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (offset < ARRAY_SIZE(s->regs)) {
|
||||
trace_msf2_sysreg_write(offset << 2, newval, s->regs[offset]);
|
||||
s->regs[offset] = newval;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%08" HWADDR_PRIx "\n", __func__,
|
||||
offset << 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sysreg_ops = {
|
||||
.read = msf2_sysreg_read,
|
||||
.write = msf2_sysreg_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void msf2_sysreg_init(Object *obj)
|
||||
{
|
||||
MSF2SysregState *s = MSF2_SYSREG(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &sysreg_ops, s, TYPE_MSF2_SYSREG,
|
||||
MSF2_SYSREG_MMIO_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_msf2_sysreg = {
|
||||
.name = TYPE_MSF2_SYSREG,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MSF2SysregState, MSF2_SYSREG_MMIO_SIZE / 4),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property msf2_sysreg_properties[] = {
|
||||
/* default divisors in Libero GUI */
|
||||
DEFINE_PROP_UINT8("apb0divisor", MSF2SysregState, apb0div, 2),
|
||||
DEFINE_PROP_UINT8("apb1divisor", MSF2SysregState, apb1div, 2),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void msf2_sysreg_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MSF2SysregState *s = MSF2_SYSREG(dev);
|
||||
|
||||
if ((s->apb0div > 32 || !is_power_of_2(s->apb0div))
|
||||
|| (s->apb1div > 32 || !is_power_of_2(s->apb1div))) {
|
||||
error_setg(errp, "Invalid apb divisor value");
|
||||
error_append_hint(errp, "apb divisor must be a power of 2"
|
||||
" and maximum value is 32\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void msf2_sysreg_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_msf2_sysreg;
|
||||
dc->reset = msf2_sysreg_reset;
|
||||
dc->props = msf2_sysreg_properties;
|
||||
dc->realize = msf2_sysreg_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo msf2_sysreg_info = {
|
||||
.name = TYPE_MSF2_SYSREG,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.class_init = msf2_sysreg_class_init,
|
||||
.instance_size = sizeof(MSF2SysregState),
|
||||
.instance_init = msf2_sysreg_init,
|
||||
};
|
||||
|
||||
static void msf2_sysreg_register_types(void)
|
||||
{
|
||||
type_register_static(&msf2_sysreg_info);
|
||||
}
|
||||
|
||||
type_init(msf2_sysreg_register_types)
|
|
@ -61,3 +61,8 @@ mps2_scc_reset(void) "MPS2 SCC: reset"
|
|||
mps2_scc_leds(char led7, char led6, char led5, char led4, char led3, char led2, char led1, char led0) "MPS2 SCC LEDs: %c%c%c%c%c%c%c%c"
|
||||
mps2_scc_cfg_write(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config write: function %d device %d data 0x%" PRIx32
|
||||
mps2_scc_cfg_read(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config read: function %d device %d data 0x%" PRIx32
|
||||
|
||||
# hw/misc/msf2-sysreg.c
|
||||
msf2_sysreg_write(uint64_t offset, uint32_t val, uint32_t prev) "msf2-sysreg write: addr 0x%08" HWADDR_PRIx " data 0x%" PRIx32 " prev 0x%" PRIx32
|
||||
msf2_sysreg_read(uint64_t offset, uint32_t val) "msf2-sysreg read: addr 0x%08" HWADDR_PRIx " data 0x%08" PRIx32
|
||||
msf2_sysreg_write_pll_status(void) "Invalid write to read only PLL status register"
|
||||
|
|
|
@ -4,6 +4,7 @@ common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
|
|||
common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o
|
||||
common-obj-$(CONFIG_STM32F2XX_SPI) += stm32f2xx_spi.o
|
||||
common-obj-$(CONFIG_MSF2) += mss-spi.o
|
||||
|
||||
obj-$(CONFIG_OMAP) += omap_spi.o
|
||||
obj-$(CONFIG_IMX) += imx_spi.o
|
||||
|
|
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
* Block model of SPI controller present in
|
||||
* Microsemi's SmartFusion2 and SmartFusion SoCs.
|
||||
*
|
||||
* Copyright (C) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* 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 "hw/ssi/mss-spi.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
#ifndef MSS_SPI_ERR_DEBUG
|
||||
#define MSS_SPI_ERR_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define DB_PRINT_L(lvl, fmt, args...) do { \
|
||||
if (MSS_SPI_ERR_DEBUG >= lvl) { \
|
||||
qemu_log("%s: " fmt "\n", __func__, ## args); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
|
||||
|
||||
#define FIFO_CAPACITY 32
|
||||
|
||||
#define R_SPI_CONTROL 0
|
||||
#define R_SPI_DFSIZE 1
|
||||
#define R_SPI_STATUS 2
|
||||
#define R_SPI_INTCLR 3
|
||||
#define R_SPI_RX 4
|
||||
#define R_SPI_TX 5
|
||||
#define R_SPI_CLKGEN 6
|
||||
#define R_SPI_SS 7
|
||||
#define R_SPI_MIS 8
|
||||
#define R_SPI_RIS 9
|
||||
|
||||
#define S_TXDONE (1 << 0)
|
||||
#define S_RXRDY (1 << 1)
|
||||
#define S_RXCHOVRF (1 << 2)
|
||||
#define S_RXFIFOFUL (1 << 4)
|
||||
#define S_RXFIFOFULNXT (1 << 5)
|
||||
#define S_RXFIFOEMP (1 << 6)
|
||||
#define S_RXFIFOEMPNXT (1 << 7)
|
||||
#define S_TXFIFOFUL (1 << 8)
|
||||
#define S_TXFIFOFULNXT (1 << 9)
|
||||
#define S_TXFIFOEMP (1 << 10)
|
||||
#define S_TXFIFOEMPNXT (1 << 11)
|
||||
#define S_FRAMESTART (1 << 12)
|
||||
#define S_SSEL (1 << 13)
|
||||
#define S_ACTIVE (1 << 14)
|
||||
|
||||
#define C_ENABLE (1 << 0)
|
||||
#define C_MODE (1 << 1)
|
||||
#define C_INTRXDATA (1 << 4)
|
||||
#define C_INTTXDATA (1 << 5)
|
||||
#define C_INTRXOVRFLO (1 << 6)
|
||||
#define C_SPS (1 << 26)
|
||||
#define C_BIGFIFO (1 << 29)
|
||||
#define C_RESET (1 << 31)
|
||||
|
||||
#define FRAMESZ_MASK 0x1F
|
||||
#define FMCOUNT_MASK 0x00FFFF00
|
||||
#define FMCOUNT_SHIFT 8
|
||||
|
||||
static void txfifo_reset(MSSSpiState *s)
|
||||
{
|
||||
fifo32_reset(&s->tx_fifo);
|
||||
|
||||
s->regs[R_SPI_STATUS] &= ~S_TXFIFOFUL;
|
||||
s->regs[R_SPI_STATUS] |= S_TXFIFOEMP;
|
||||
}
|
||||
|
||||
static void rxfifo_reset(MSSSpiState *s)
|
||||
{
|
||||
fifo32_reset(&s->rx_fifo);
|
||||
|
||||
s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL;
|
||||
s->regs[R_SPI_STATUS] |= S_RXFIFOEMP;
|
||||
}
|
||||
|
||||
static void set_fifodepth(MSSSpiState *s)
|
||||
{
|
||||
unsigned int size = s->regs[R_SPI_DFSIZE] & FRAMESZ_MASK;
|
||||
|
||||
if (size <= 8) {
|
||||
s->fifo_depth = 32;
|
||||
} else if (size <= 16) {
|
||||
s->fifo_depth = 16;
|
||||
} else if (size <= 32) {
|
||||
s->fifo_depth = 8;
|
||||
} else {
|
||||
s->fifo_depth = 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_mis(MSSSpiState *s)
|
||||
{
|
||||
uint32_t reg = s->regs[R_SPI_CONTROL];
|
||||
uint32_t tmp;
|
||||
|
||||
/*
|
||||
* form the Control register interrupt enable bits
|
||||
* same as RIS, MIS and Interrupt clear registers for simplicity
|
||||
*/
|
||||
tmp = ((reg & C_INTRXOVRFLO) >> 4) | ((reg & C_INTRXDATA) >> 3) |
|
||||
((reg & C_INTTXDATA) >> 5);
|
||||
s->regs[R_SPI_MIS] |= tmp & s->regs[R_SPI_RIS];
|
||||
}
|
||||
|
||||
static void spi_update_irq(MSSSpiState *s)
|
||||
{
|
||||
int irq;
|
||||
|
||||
update_mis(s);
|
||||
irq = !!(s->regs[R_SPI_MIS]);
|
||||
|
||||
qemu_set_irq(s->irq, irq);
|
||||
}
|
||||
|
||||
static void mss_spi_reset(DeviceState *d)
|
||||
{
|
||||
MSSSpiState *s = MSS_SPI(d);
|
||||
|
||||
memset(s->regs, 0, sizeof s->regs);
|
||||
s->regs[R_SPI_CONTROL] = 0x80000102;
|
||||
s->regs[R_SPI_DFSIZE] = 0x4;
|
||||
s->regs[R_SPI_STATUS] = S_SSEL | S_TXFIFOEMP | S_RXFIFOEMP;
|
||||
s->regs[R_SPI_CLKGEN] = 0x7;
|
||||
s->regs[R_SPI_RIS] = 0x0;
|
||||
|
||||
s->fifo_depth = 4;
|
||||
s->frame_count = 1;
|
||||
s->enabled = false;
|
||||
|
||||
rxfifo_reset(s);
|
||||
txfifo_reset(s);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
spi_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
MSSSpiState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_SPI_RX:
|
||||
s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL;
|
||||
s->regs[R_SPI_STATUS] &= ~S_RXCHOVRF;
|
||||
ret = fifo32_pop(&s->rx_fifo);
|
||||
if (fifo32_is_empty(&s->rx_fifo)) {
|
||||
s->regs[R_SPI_STATUS] |= S_RXFIFOEMP;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_SPI_MIS:
|
||||
update_mis(s);
|
||||
ret = s->regs[R_SPI_MIS];
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < ARRAY_SIZE(s->regs)) {
|
||||
ret = s->regs[addr];
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__,
|
||||
addr * 4);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DB_PRINT("addr=0x%" HWADDR_PRIx " = 0x%" PRIx32, addr * 4, ret);
|
||||
spi_update_irq(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void assert_cs(MSSSpiState *s)
|
||||
{
|
||||
qemu_set_irq(s->cs_line, 0);
|
||||
}
|
||||
|
||||
static void deassert_cs(MSSSpiState *s)
|
||||
{
|
||||
qemu_set_irq(s->cs_line, 1);
|
||||
}
|
||||
|
||||
static void spi_flush_txfifo(MSSSpiState *s)
|
||||
{
|
||||
uint32_t tx;
|
||||
uint32_t rx;
|
||||
bool sps = !!(s->regs[R_SPI_CONTROL] & C_SPS);
|
||||
|
||||
/*
|
||||
* Chip Select(CS) is automatically controlled by this controller.
|
||||
* If SPS bit is set in Control register then CS is asserted
|
||||
* until all the frames set in frame count of Control register are
|
||||
* transferred. If SPS is not set then CS pulses between frames.
|
||||
* Note that Slave Select register specifies which of the CS line
|
||||
* has to be controlled automatically by controller. Bits SS[7:1] are for
|
||||
* masters in FPGA fabric since we model only Microcontroller subsystem
|
||||
* of Smartfusion2 we control only one CS(SS[0]) line.
|
||||
*/
|
||||
while (!fifo32_is_empty(&s->tx_fifo) && s->frame_count) {
|
||||
assert_cs(s);
|
||||
|
||||
s->regs[R_SPI_STATUS] &= ~(S_TXDONE | S_RXRDY);
|
||||
|
||||
tx = fifo32_pop(&s->tx_fifo);
|
||||
DB_PRINT("data tx:0x%" PRIx32, tx);
|
||||
rx = ssi_transfer(s->spi, tx);
|
||||
DB_PRINT("data rx:0x%" PRIx32, rx);
|
||||
|
||||
if (fifo32_num_used(&s->rx_fifo) == s->fifo_depth) {
|
||||
s->regs[R_SPI_STATUS] |= S_RXCHOVRF;
|
||||
s->regs[R_SPI_RIS] |= S_RXCHOVRF;
|
||||
} else {
|
||||
fifo32_push(&s->rx_fifo, rx);
|
||||
s->regs[R_SPI_STATUS] &= ~S_RXFIFOEMP;
|
||||
if (fifo32_num_used(&s->rx_fifo) == (s->fifo_depth - 1)) {
|
||||
s->regs[R_SPI_STATUS] |= S_RXFIFOFULNXT;
|
||||
} else if (fifo32_num_used(&s->rx_fifo) == s->fifo_depth) {
|
||||
s->regs[R_SPI_STATUS] |= S_RXFIFOFUL;
|
||||
}
|
||||
}
|
||||
s->frame_count--;
|
||||
if (!sps) {
|
||||
deassert_cs(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->frame_count) {
|
||||
s->frame_count = (s->regs[R_SPI_CONTROL] & FMCOUNT_MASK) >>
|
||||
FMCOUNT_SHIFT;
|
||||
deassert_cs(s);
|
||||
s->regs[R_SPI_RIS] |= S_TXDONE | S_RXRDY;
|
||||
s->regs[R_SPI_STATUS] |= S_TXDONE | S_RXRDY;
|
||||
}
|
||||
}
|
||||
|
||||
static void spi_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
MSSSpiState *s = opaque;
|
||||
uint32_t value = val64;
|
||||
|
||||
DB_PRINT("addr=0x%" HWADDR_PRIx " =0x%" PRIx32, addr, value);
|
||||
addr >>= 2;
|
||||
|
||||
switch (addr) {
|
||||
case R_SPI_TX:
|
||||
/* adding to already full FIFO */
|
||||
if (fifo32_num_used(&s->tx_fifo) == s->fifo_depth) {
|
||||
break;
|
||||
}
|
||||
s->regs[R_SPI_STATUS] &= ~S_TXFIFOEMP;
|
||||
fifo32_push(&s->tx_fifo, value);
|
||||
if (fifo32_num_used(&s->tx_fifo) == (s->fifo_depth - 1)) {
|
||||
s->regs[R_SPI_STATUS] |= S_TXFIFOFULNXT;
|
||||
} else if (fifo32_num_used(&s->tx_fifo) == s->fifo_depth) {
|
||||
s->regs[R_SPI_STATUS] |= S_TXFIFOFUL;
|
||||
}
|
||||
if (s->enabled) {
|
||||
spi_flush_txfifo(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_SPI_CONTROL:
|
||||
s->regs[R_SPI_CONTROL] = value;
|
||||
if (value & C_BIGFIFO) {
|
||||
set_fifodepth(s);
|
||||
} else {
|
||||
s->fifo_depth = 4;
|
||||
}
|
||||
s->enabled = value & C_ENABLE;
|
||||
s->frame_count = (value & FMCOUNT_MASK) >> FMCOUNT_SHIFT;
|
||||
if (value & C_RESET) {
|
||||
mss_spi_reset(DEVICE(s));
|
||||
}
|
||||
break;
|
||||
|
||||
case R_SPI_DFSIZE:
|
||||
if (s->enabled) {
|
||||
break;
|
||||
}
|
||||
s->regs[R_SPI_DFSIZE] = value;
|
||||
break;
|
||||
|
||||
case R_SPI_INTCLR:
|
||||
s->regs[R_SPI_INTCLR] = value;
|
||||
if (value & S_TXDONE) {
|
||||
s->regs[R_SPI_RIS] &= ~S_TXDONE;
|
||||
}
|
||||
if (value & S_RXRDY) {
|
||||
s->regs[R_SPI_RIS] &= ~S_RXRDY;
|
||||
}
|
||||
if (value & S_RXCHOVRF) {
|
||||
s->regs[R_SPI_RIS] &= ~S_RXCHOVRF;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_SPI_MIS:
|
||||
case R_SPI_STATUS:
|
||||
case R_SPI_RIS:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Write to read only register 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr * 4);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < ARRAY_SIZE(s->regs)) {
|
||||
s->regs[addr] = value;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__,
|
||||
addr * 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
spi_update_irq(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps spi_ops = {
|
||||
.read = spi_read,
|
||||
.write = spi_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
||||
|
||||
static void mss_spi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MSSSpiState *s = MSS_SPI(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
s->spi = ssi_create_bus(dev, "spi");
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
ssi_auto_connect_slaves(dev, &s->cs_line, s->spi);
|
||||
sysbus_init_irq(sbd, &s->cs_line);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s,
|
||||
TYPE_MSS_SPI, R_SPI_MAX * 4);
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
|
||||
fifo32_create(&s->tx_fifo, FIFO_CAPACITY);
|
||||
fifo32_create(&s->rx_fifo, FIFO_CAPACITY);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_mss_spi = {
|
||||
.name = TYPE_MSS_SPI,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_FIFO32(tx_fifo, MSSSpiState),
|
||||
VMSTATE_FIFO32(rx_fifo, MSSSpiState),
|
||||
VMSTATE_UINT32_ARRAY(regs, MSSSpiState, R_SPI_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void mss_spi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = mss_spi_realize;
|
||||
dc->reset = mss_spi_reset;
|
||||
dc->vmsd = &vmstate_mss_spi;
|
||||
}
|
||||
|
||||
static const TypeInfo mss_spi_info = {
|
||||
.name = TYPE_MSS_SPI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MSSSpiState),
|
||||
.class_init = mss_spi_class_init,
|
||||
};
|
||||
|
||||
static void mss_spi_register_types(void)
|
||||
{
|
||||
type_register_static(&mss_spi_info);
|
||||
}
|
||||
|
||||
type_init(mss_spi_register_types)
|
|
@ -42,3 +42,4 @@ common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
|
|||
|
||||
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
|
||||
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
|
||||
common-obj-$(CONFIG_MSF2) += mss-timer.o
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* Block model of System timer present in
|
||||
* Microsemi's SmartFusion2 and SmartFusion SoCs.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>.
|
||||
*
|
||||
* 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/main-loop.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/timer/mss-timer.h"
|
||||
|
||||
#ifndef MSS_TIMER_ERR_DEBUG
|
||||
#define MSS_TIMER_ERR_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define DB_PRINT_L(lvl, fmt, args...) do { \
|
||||
if (MSS_TIMER_ERR_DEBUG >= lvl) { \
|
||||
qemu_log("%s: " fmt "\n", __func__, ## args); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
|
||||
|
||||
#define R_TIM_VAL 0
|
||||
#define R_TIM_LOADVAL 1
|
||||
#define R_TIM_BGLOADVAL 2
|
||||
#define R_TIM_CTRL 3
|
||||
#define R_TIM_RIS 4
|
||||
#define R_TIM_MIS 5
|
||||
|
||||
#define TIMER_CTRL_ENBL (1 << 0)
|
||||
#define TIMER_CTRL_ONESHOT (1 << 1)
|
||||
#define TIMER_CTRL_INTR (1 << 2)
|
||||
#define TIMER_RIS_ACK (1 << 0)
|
||||
#define TIMER_RST_CLR (1 << 6)
|
||||
#define TIMER_MODE (1 << 0)
|
||||
|
||||
static void timer_update_irq(struct Msf2Timer *st)
|
||||
{
|
||||
bool isr, ier;
|
||||
|
||||
isr = !!(st->regs[R_TIM_RIS] & TIMER_RIS_ACK);
|
||||
ier = !!(st->regs[R_TIM_CTRL] & TIMER_CTRL_INTR);
|
||||
qemu_set_irq(st->irq, (ier && isr));
|
||||
}
|
||||
|
||||
static void timer_update(struct Msf2Timer *st)
|
||||
{
|
||||
uint64_t count;
|
||||
|
||||
if (!(st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL)) {
|
||||
ptimer_stop(st->ptimer);
|
||||
return;
|
||||
}
|
||||
|
||||
count = st->regs[R_TIM_LOADVAL];
|
||||
ptimer_set_limit(st->ptimer, count, 1);
|
||||
ptimer_run(st->ptimer, 1);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
timer_read(void *opaque, hwaddr offset, unsigned int size)
|
||||
{
|
||||
MSSTimerState *t = opaque;
|
||||
hwaddr addr;
|
||||
struct Msf2Timer *st;
|
||||
uint32_t ret = 0;
|
||||
int timer = 0;
|
||||
int isr;
|
||||
int ier;
|
||||
|
||||
addr = offset >> 2;
|
||||
/*
|
||||
* Two independent timers has same base address.
|
||||
* Based on address passed figure out which timer is being used.
|
||||
*/
|
||||
if ((addr >= R_TIM1_MAX) && (addr < NUM_TIMERS * R_TIM1_MAX)) {
|
||||
timer = 1;
|
||||
addr -= R_TIM1_MAX;
|
||||
}
|
||||
|
||||
st = &t->timers[timer];
|
||||
|
||||
switch (addr) {
|
||||
case R_TIM_VAL:
|
||||
ret = ptimer_get_count(st->ptimer);
|
||||
break;
|
||||
|
||||
case R_TIM_MIS:
|
||||
isr = !!(st->regs[R_TIM_RIS] & TIMER_RIS_ACK);
|
||||
ier = !!(st->regs[R_TIM_CTRL] & TIMER_CTRL_INTR);
|
||||
ret = ier & isr;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < R_TIM1_MAX) {
|
||||
ret = st->regs[addr];
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
TYPE_MSS_TIMER": 64-bit mode not supported\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DB_PRINT("timer=%d 0x%" HWADDR_PRIx "=0x%" PRIx32, timer, offset,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
timer_write(void *opaque, hwaddr offset,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
MSSTimerState *t = opaque;
|
||||
hwaddr addr;
|
||||
struct Msf2Timer *st;
|
||||
int timer = 0;
|
||||
uint32_t value = val64;
|
||||
|
||||
addr = offset >> 2;
|
||||
/*
|
||||
* Two independent timers has same base address.
|
||||
* Based on addr passed figure out which timer is being used.
|
||||
*/
|
||||
if ((addr >= R_TIM1_MAX) && (addr < NUM_TIMERS * R_TIM1_MAX)) {
|
||||
timer = 1;
|
||||
addr -= R_TIM1_MAX;
|
||||
}
|
||||
|
||||
st = &t->timers[timer];
|
||||
|
||||
DB_PRINT("addr=0x%" HWADDR_PRIx " val=0x%" PRIx32 " (timer=%d)", offset,
|
||||
value, timer);
|
||||
|
||||
switch (addr) {
|
||||
case R_TIM_CTRL:
|
||||
st->regs[R_TIM_CTRL] = value;
|
||||
timer_update(st);
|
||||
break;
|
||||
|
||||
case R_TIM_RIS:
|
||||
if (value & TIMER_RIS_ACK) {
|
||||
st->regs[R_TIM_RIS] &= ~TIMER_RIS_ACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_TIM_LOADVAL:
|
||||
st->regs[R_TIM_LOADVAL] = value;
|
||||
if (st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL) {
|
||||
timer_update(st);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_TIM_BGLOADVAL:
|
||||
st->regs[R_TIM_BGLOADVAL] = value;
|
||||
st->regs[R_TIM_LOADVAL] = value;
|
||||
break;
|
||||
|
||||
case R_TIM_VAL:
|
||||
case R_TIM_MIS:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addr < R_TIM1_MAX) {
|
||||
st->regs[addr] = value;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
TYPE_MSS_TIMER": 64-bit mode not supported\n");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
timer_update_irq(st);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct Msf2Timer *st = opaque;
|
||||
|
||||
st->regs[R_TIM_RIS] |= TIMER_RIS_ACK;
|
||||
|
||||
if (!(st->regs[R_TIM_CTRL] & TIMER_CTRL_ONESHOT)) {
|
||||
timer_update(st);
|
||||
}
|
||||
timer_update_irq(st);
|
||||
}
|
||||
|
||||
static void mss_timer_init(Object *obj)
|
||||
{
|
||||
MSSTimerState *t = MSS_TIMER(obj);
|
||||
int i;
|
||||
|
||||
/* Init all the ptimers. */
|
||||
for (i = 0; i < NUM_TIMERS; i++) {
|
||||
struct Msf2Timer *st = &t->timers[i];
|
||||
|
||||
st->bh = qemu_bh_new(timer_hit, st);
|
||||
st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(st->ptimer, t->freq_hz);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &st->irq);
|
||||
}
|
||||
|
||||
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, TYPE_MSS_TIMER,
|
||||
NUM_TIMERS * R_TIM1_MAX * 4);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &t->mmio);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_timers = {
|
||||
.name = "mss-timer-block",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PTIMER(ptimer, struct Msf2Timer),
|
||||
VMSTATE_UINT32_ARRAY(regs, struct Msf2Timer, R_TIM1_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_mss_timer = {
|
||||
.name = TYPE_MSS_TIMER,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(freq_hz, MSSTimerState),
|
||||
VMSTATE_STRUCT_ARRAY(timers, MSSTimerState, NUM_TIMERS, 0,
|
||||
vmstate_timers, struct Msf2Timer),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property mss_timer_properties[] = {
|
||||
/* Libero GUI shows 100Mhz as default for clocks */
|
||||
DEFINE_PROP_UINT32("clock-frequency", MSSTimerState, freq_hz,
|
||||
100 * 1000000),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void mss_timer_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = mss_timer_properties;
|
||||
dc->vmsd = &vmstate_mss_timer;
|
||||
}
|
||||
|
||||
static const TypeInfo mss_timer_info = {
|
||||
.name = TYPE_MSS_TIMER,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MSSTimerState),
|
||||
.instance_init = mss_timer_init,
|
||||
.class_init = mss_timer_class_init,
|
||||
};
|
||||
|
||||
static void mss_timer_register_types(void)
|
||||
{
|
||||
type_register_static(&mss_timer_info);
|
||||
}
|
||||
|
||||
type_init(mss_timer_register_types)
|
|
@ -450,19 +450,44 @@ static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
|
|||
s->writeh = (uint16_t) value;
|
||||
}
|
||||
|
||||
static uint64_t omap_gp_timer_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
case 2:
|
||||
return omap_gp_timer_readh(opaque, addr);
|
||||
case 4:
|
||||
return omap_gp_timer_readw(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_gp_timer_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
omap_badwidth_write32(opaque, addr, value);
|
||||
break;
|
||||
case 2:
|
||||
omap_gp_timer_writeh(opaque, addr, value);
|
||||
break;
|
||||
case 4:
|
||||
omap_gp_timer_write(opaque, addr, value);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_gp_timer_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap_badwidth_read32,
|
||||
omap_gp_timer_readh,
|
||||
omap_gp_timer_readw,
|
||||
},
|
||||
.write = {
|
||||
omap_badwidth_write32,
|
||||
omap_gp_timer_writeh,
|
||||
omap_gp_timer_write,
|
||||
},
|
||||
},
|
||||
.read = omap_gp_timer_readfn,
|
||||
.write = omap_gp_timer_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
|
|
@ -68,25 +68,32 @@ static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
|
|||
}
|
||||
}
|
||||
|
||||
static void omap_synctimer_write(void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
static uint64_t omap_synctimer_readfn(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return omap_badwidth_read32(opaque, addr);
|
||||
case 2:
|
||||
return omap_synctimer_readh(opaque, addr);
|
||||
case 4:
|
||||
return omap_synctimer_readw(opaque, addr);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_synctimer_writefn(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
OMAP_BAD_REG(addr);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps omap_synctimer_ops = {
|
||||
.old_mmio = {
|
||||
.read = {
|
||||
omap_badwidth_read32,
|
||||
omap_synctimer_readh,
|
||||
omap_synctimer_readw,
|
||||
},
|
||||
.write = {
|
||||
omap_badwidth_write32,
|
||||
omap_synctimer_write,
|
||||
omap_synctimer_write,
|
||||
},
|
||||
},
|
||||
.read = omap_synctimer_readfn,
|
||||
.write = omap_synctimer_writefn,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Microsemi Smartfusion2 SoC
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef HW_ARM_MSF2_SOC_H
|
||||
#define HW_ARM_MSF2_SOC_H
|
||||
|
||||
#include "hw/arm/armv7m.h"
|
||||
#include "hw/timer/mss-timer.h"
|
||||
#include "hw/misc/msf2-sysreg.h"
|
||||
#include "hw/ssi/mss-spi.h"
|
||||
|
||||
#define TYPE_MSF2_SOC "msf2-soc"
|
||||
#define MSF2_SOC(obj) OBJECT_CHECK(MSF2State, (obj), TYPE_MSF2_SOC)
|
||||
|
||||
#define MSF2_NUM_SPIS 2
|
||||
#define MSF2_NUM_UARTS 2
|
||||
|
||||
/*
|
||||
* System timer consists of two programmable 32-bit
|
||||
* decrementing counters that generate individual interrupts to
|
||||
* the Cortex-M3 processor
|
||||
*/
|
||||
#define MSF2_NUM_TIMERS 2
|
||||
|
||||
typedef struct MSF2State {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
ARMv7MState armv7m;
|
||||
|
||||
char *cpu_type;
|
||||
char *part_name;
|
||||
uint64_t envm_size;
|
||||
uint64_t esram_size;
|
||||
|
||||
uint32_t m3clk;
|
||||
uint8_t apb0div;
|
||||
uint8_t apb1div;
|
||||
|
||||
MSF2SysregState sysreg;
|
||||
MSSTimerState timer;
|
||||
MSSSpiState spi[MSF2_NUM_SPIS];
|
||||
} MSF2State;
|
||||
|
||||
#endif
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
/* Highest permitted number of exceptions (architectural limit) */
|
||||
#define NVIC_MAX_VECTORS 512
|
||||
/* Number of internal exceptions */
|
||||
#define NVIC_INTERNAL_VECTORS 16
|
||||
|
||||
typedef struct VecInfo {
|
||||
/* Exception priorities can range from -3 to 255; only the unmodifiable
|
||||
|
@ -41,13 +43,38 @@ typedef struct NVICState {
|
|||
ARMCPU *cpu;
|
||||
|
||||
VecInfo vectors[NVIC_MAX_VECTORS];
|
||||
uint32_t prigroup;
|
||||
/* If the v8M security extension is implemented, some of the internal
|
||||
* exceptions are banked between security states (ie there exists both
|
||||
* a Secure and a NonSecure version of the exception and its state):
|
||||
* HardFault, MemManage, UsageFault, SVCall, PendSV, SysTick (R_PJHV)
|
||||
* The rest (including all the external exceptions) are not banked, though
|
||||
* they may be configurable to target either Secure or NonSecure state.
|
||||
* We store the secure exception state in sec_vectors[] for the banked
|
||||
* exceptions, and otherwise use only vectors[] (including for exceptions
|
||||
* like SecureFault that unconditionally target Secure state).
|
||||
* Entries in sec_vectors[] for non-banked exception numbers are unused.
|
||||
*/
|
||||
VecInfo sec_vectors[NVIC_INTERNAL_VECTORS];
|
||||
/* The PRIGROUP field in AIRCR is banked */
|
||||
uint32_t prigroup[M_REG_NUM_BANKS];
|
||||
|
||||
/* vectpending and exception_prio are both cached state that can
|
||||
* be recalculated from the vectors[] array and the prigroup field.
|
||||
/* v8M NVIC_ITNS state (stored as a bool per bit) */
|
||||
bool itns[NVIC_MAX_VECTORS];
|
||||
|
||||
/* The following fields are all cached state that can be recalculated
|
||||
* from the vectors[] and sec_vectors[] arrays and the prigroup field:
|
||||
* - vectpending
|
||||
* - vectpending_is_secure
|
||||
* - exception_prio
|
||||
* - vectpending_prio
|
||||
*/
|
||||
unsigned int vectpending; /* highest prio pending enabled exception */
|
||||
/* true if vectpending is a banked secure exception, ie it is in
|
||||
* sec_vectors[] rather than vectors[]
|
||||
*/
|
||||
bool vectpending_is_s_banked;
|
||||
int exception_prio; /* group prio of the highest prio active exception */
|
||||
int vectpending_prio; /* group prio of the exeception in vectpending */
|
||||
|
||||
MemoryRegion sysregmem;
|
||||
MemoryRegion sysreg_ns_mem;
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Microsemi SmartFusion2 SYSREG
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef HW_MSF2_SYSREG_H
|
||||
#define HW_MSF2_SYSREG_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
enum {
|
||||
ESRAM_CR = 0x00 / 4,
|
||||
ESRAM_MAX_LAT,
|
||||
DDR_CR,
|
||||
ENVM_CR,
|
||||
ENVM_REMAP_BASE_CR,
|
||||
ENVM_REMAP_FAB_CR,
|
||||
CC_CR,
|
||||
CC_REGION_CR,
|
||||
CC_LOCK_BASE_ADDR_CR,
|
||||
CC_FLUSH_INDX_CR,
|
||||
DDRB_BUF_TIMER_CR,
|
||||
DDRB_NB_ADDR_CR,
|
||||
DDRB_NB_SIZE_CR,
|
||||
DDRB_CR,
|
||||
|
||||
SOFT_RESET_CR = 0x48 / 4,
|
||||
M3_CR,
|
||||
|
||||
GPIO_SYSRESET_SEL_CR = 0x58 / 4,
|
||||
|
||||
MDDR_CR = 0x60 / 4,
|
||||
|
||||
MSSDDR_PLL_STATUS_LOW_CR = 0x90 / 4,
|
||||
MSSDDR_PLL_STATUS_HIGH_CR,
|
||||
MSSDDR_FACC1_CR,
|
||||
MSSDDR_FACC2_CR,
|
||||
|
||||
MSSDDR_PLL_STATUS = 0x150 / 4,
|
||||
};
|
||||
|
||||
#define MSF2_SYSREG_MMIO_SIZE 0x300
|
||||
|
||||
#define TYPE_MSF2_SYSREG "msf2-sysreg"
|
||||
#define MSF2_SYSREG(obj) OBJECT_CHECK(MSF2SysregState, (obj), TYPE_MSF2_SYSREG)
|
||||
|
||||
typedef struct MSF2SysregState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint8_t apb0div;
|
||||
uint8_t apb1div;
|
||||
|
||||
uint32_t regs[MSF2_SYSREG_MMIO_SIZE / 4];
|
||||
} MSF2SysregState;
|
||||
|
||||
#endif /* HW_MSF2_SYSREG_H */
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Microsemi SmartFusion2 SPI
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef HW_MSS_SPI_H
|
||||
#define HW_MSS_SPI_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "qemu/fifo32.h"
|
||||
|
||||
#define TYPE_MSS_SPI "mss-spi"
|
||||
#define MSS_SPI(obj) OBJECT_CHECK(MSSSpiState, (obj), TYPE_MSS_SPI)
|
||||
|
||||
#define R_SPI_MAX 16
|
||||
|
||||
typedef struct MSSSpiState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
qemu_irq irq;
|
||||
|
||||
qemu_irq cs_line;
|
||||
|
||||
SSIBus *spi;
|
||||
|
||||
Fifo32 rx_fifo;
|
||||
Fifo32 tx_fifo;
|
||||
|
||||
int fifo_depth;
|
||||
uint32_t frame_count;
|
||||
bool enabled;
|
||||
|
||||
uint32_t regs[R_SPI_MAX];
|
||||
} MSSSpiState;
|
||||
|
||||
#endif /* HW_MSS_SPI_H */
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Microsemi SmartFusion2 Timer.
|
||||
*
|
||||
* Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef HW_MSS_TIMER_H
|
||||
#define HW_MSS_TIMER_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
#define TYPE_MSS_TIMER "mss-timer"
|
||||
#define MSS_TIMER(obj) OBJECT_CHECK(MSSTimerState, \
|
||||
(obj), TYPE_MSS_TIMER)
|
||||
|
||||
/*
|
||||
* There are two 32-bit down counting timers.
|
||||
* Timers 1 and 2 can be concatenated into a single 64-bit Timer
|
||||
* that operates either in Periodic mode or in One-shot mode.
|
||||
* Writing 1 to the TIM64_MODE register bit 0 sets the Timers in 64-bit mode.
|
||||
* In 64-bit mode, writing to the 32-bit registers has no effect.
|
||||
* Similarly, in 32-bit mode, writing to the 64-bit mode registers
|
||||
* has no effect. Only two 32-bit timers are supported currently.
|
||||
*/
|
||||
#define NUM_TIMERS 2
|
||||
|
||||
#define R_TIM1_MAX 6
|
||||
|
||||
struct Msf2Timer {
|
||||
QEMUBH *bh;
|
||||
ptimer_state *ptimer;
|
||||
|
||||
uint32_t regs[R_TIM1_MAX];
|
||||
qemu_irq irq;
|
||||
};
|
||||
|
||||
typedef struct MSSTimerState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
uint32_t freq_hz;
|
||||
struct Msf2Timer timers[NUM_TIMERS];
|
||||
} MSSTimerState;
|
||||
|
||||
#endif /* HW_MSS_TIMER_H */
|
|
@ -187,6 +187,13 @@ static void arm_cpu_reset(CPUState *s)
|
|||
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
env->v7m.secure = true;
|
||||
} else {
|
||||
/* This bit resets to 0 if security is supported, but 1 if
|
||||
* it is not. The bit is not present in v7M, but we set it
|
||||
* here so we can avoid having to make checks on it conditional
|
||||
* on ARM_FEATURE_V8 (we don't let the guest see the bit).
|
||||
*/
|
||||
env->v7m.aircr = R_V7M_AIRCR_BFHFNMINS_MASK;
|
||||
}
|
||||
|
||||
/* In v7M the reset value of this bit is IMPDEF, but ARM recommends
|
||||
|
|
|
@ -449,6 +449,7 @@ typedef struct CPUARMState {
|
|||
int exception;
|
||||
uint32_t primask[M_REG_NUM_BANKS];
|
||||
uint32_t faultmask[M_REG_NUM_BANKS];
|
||||
uint32_t aircr; /* only holds r/w state if security extn implemented */
|
||||
uint32_t secure; /* Is CPU in Secure state? (not guest visible) */
|
||||
} v7m;
|
||||
|
||||
|
@ -1200,6 +1201,17 @@ FIELD(V7M_CCR, STKALIGN, 9, 1)
|
|||
FIELD(V7M_CCR, DC, 16, 1)
|
||||
FIELD(V7M_CCR, IC, 17, 1)
|
||||
|
||||
/* V7M AIRCR bits */
|
||||
FIELD(V7M_AIRCR, VECTRESET, 0, 1)
|
||||
FIELD(V7M_AIRCR, VECTCLRACTIVE, 1, 1)
|
||||
FIELD(V7M_AIRCR, SYSRESETREQ, 2, 1)
|
||||
FIELD(V7M_AIRCR, SYSRESETREQS, 3, 1)
|
||||
FIELD(V7M_AIRCR, PRIGROUP, 8, 3)
|
||||
FIELD(V7M_AIRCR, BFHFNMINS, 13, 1)
|
||||
FIELD(V7M_AIRCR, PRIS, 14, 1)
|
||||
FIELD(V7M_AIRCR, ENDIANNESS, 15, 1)
|
||||
FIELD(V7M_AIRCR, VECTKEY, 16, 16)
|
||||
|
||||
/* V7M CFSR bits for MMFSR */
|
||||
FIELD(V7M_CFSR, IACCVIOL, 0, 1)
|
||||
FIELD(V7M_CFSR, DACCVIOL, 1, 1)
|
||||
|
@ -1451,19 +1463,42 @@ static inline bool armv7m_nvic_can_take_pending_exception(void *opaque)
|
|||
return true;
|
||||
}
|
||||
#endif
|
||||
void armv7m_nvic_set_pending(void *opaque, int irq);
|
||||
void armv7m_nvic_acknowledge_irq(void *opaque);
|
||||
/**
|
||||
* armv7m_nvic_set_pending: mark the specified exception as pending
|
||||
* @opaque: the NVIC
|
||||
* @irq: the exception number to mark pending
|
||||
* @secure: false for non-banked exceptions or for the nonsecure
|
||||
* version of a banked exception, true for the secure version of a banked
|
||||
* exception.
|
||||
*
|
||||
* Marks the specified exception as pending. Note that we will assert()
|
||||
* if @secure is true and @irq does not specify one of the fixed set
|
||||
* of architecturally banked exceptions.
|
||||
*/
|
||||
void armv7m_nvic_set_pending(void *opaque, int irq, bool secure);
|
||||
/**
|
||||
* armv7m_nvic_acknowledge_irq: make highest priority pending exception active
|
||||
* @opaque: the NVIC
|
||||
*
|
||||
* Move the current highest priority pending exception from the pending
|
||||
* state to the active state, and update v7m.exception to indicate that
|
||||
* it is the exception currently being handled.
|
||||
*
|
||||
* Returns: true if exception should be taken to Secure state, false for NS
|
||||
*/
|
||||
bool armv7m_nvic_acknowledge_irq(void *opaque);
|
||||
/**
|
||||
* armv7m_nvic_complete_irq: complete specified interrupt or exception
|
||||
* @opaque: the NVIC
|
||||
* @irq: the exception number to complete
|
||||
* @secure: true if this exception was secure
|
||||
*
|
||||
* Returns: -1 if the irq was not active
|
||||
* 1 if completing this irq brought us back to base (no active irqs)
|
||||
* 0 if there is still an irq active after this one was completed
|
||||
* (Ignoring -1, this is the same as the RETTOBASE value before completion.)
|
||||
*/
|
||||
int armv7m_nvic_complete_irq(void *opaque, int irq);
|
||||
int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure);
|
||||
/**
|
||||
* armv7m_nvic_raw_execution_priority: return the raw execution priority
|
||||
* @opaque: the NVIC
|
||||
|
@ -1474,6 +1509,21 @@ int armv7m_nvic_complete_irq(void *opaque, int irq);
|
|||
* (v8M ARM ARM I_PKLD.)
|
||||
*/
|
||||
int armv7m_nvic_raw_execution_priority(void *opaque);
|
||||
/**
|
||||
* armv7m_nvic_neg_prio_requested: return true if the requested execution
|
||||
* priority is negative for the specified security state.
|
||||
* @opaque: the NVIC
|
||||
* @secure: the security state to test
|
||||
* This corresponds to the pseudocode IsReqExecPriNeg().
|
||||
*/
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure);
|
||||
#else
|
||||
static inline bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Interface for defining coprocessor registers.
|
||||
* Registers are defined in tables of arm_cp_reginfo structs
|
||||
|
@ -2259,11 +2309,7 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
|
|||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
ARMMMUIdx mmu_idx = el == 0 ? ARMMMUIdx_MUser : ARMMMUIdx_MPriv;
|
||||
|
||||
/* Execution priority is negative if FAULTMASK is set or
|
||||
* we're in a HardFault or NMI handler.
|
||||
*/
|
||||
if ((env->v7m.exception > 0 && env->v7m.exception <= 3)
|
||||
|| env->v7m.faultmask[env->v7m.secure]) {
|
||||
if (armv7m_nvic_neg_prio_requested(env->nvic, env->v7m.secure)) {
|
||||
mmu_idx = ARMMMUIdx_MNegPri;
|
||||
}
|
||||
|
||||
|
|
|
@ -6218,6 +6218,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
bool return_to_sp_process = false;
|
||||
bool return_to_handler = false;
|
||||
bool rettobase = false;
|
||||
bool exc_secure = false;
|
||||
|
||||
/* We can only get here from an EXCP_EXCEPTION_EXIT, and
|
||||
* gen_bx_excret() enforces the architectural rule
|
||||
|
@ -6256,16 +6257,17 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
* which security state's faultmask to clear. (v8M ARM ARM R_KBNF.)
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
int es = excret & R_V7M_EXCRET_ES_MASK;
|
||||
exc_secure = excret & R_V7M_EXCRET_ES_MASK;
|
||||
if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
|
||||
env->v7m.faultmask[es] = 0;
|
||||
env->v7m.faultmask[exc_secure] = 0;
|
||||
}
|
||||
} else {
|
||||
env->v7m.faultmask[M_REG_NS] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception)) {
|
||||
switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception,
|
||||
exc_secure)) {
|
||||
case -1:
|
||||
/* attempt to exit an exception that isn't active */
|
||||
ufault = true;
|
||||
|
@ -6306,7 +6308,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
* stack, directly take a usage fault on the current stack.
|
||||
*/
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||
v7m_exception_taken(cpu, excret);
|
||||
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
|
||||
"stackframe: failed exception return integrity check\n");
|
||||
|
@ -6345,8 +6347,11 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
* exception return excret specified then this is a UsageFault.
|
||||
*/
|
||||
if (return_to_handler != arm_v7m_is_handler_mode(env)) {
|
||||
/* Take an INVPC UsageFault by pushing the stack again. */
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
/* Take an INVPC UsageFault by pushing the stack again.
|
||||
* TODO: the v8M version of this code should target the
|
||||
* background state for this exception.
|
||||
*/
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
|
||||
v7m_push_stack(cpu);
|
||||
v7m_exception_taken(cpu, excret);
|
||||
|
@ -6406,20 +6411,20 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
handle it. */
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_UDEF:
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
|
||||
break;
|
||||
case EXCP_NOCP:
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
|
||||
break;
|
||||
case EXCP_INVSTATE:
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
/* The PC already points to the next instruction. */
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC);
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
|
||||
break;
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
case EXCP_DATA_ABORT:
|
||||
|
@ -6443,7 +6448,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
env->v7m.bfar);
|
||||
break;
|
||||
}
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS);
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
|
||||
break;
|
||||
default:
|
||||
/* All other FSR values are either MPU faults or "can't happen
|
||||
|
@ -6463,7 +6468,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
env->v7m.mmfar[env->v7m.secure]);
|
||||
break;
|
||||
}
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM,
|
||||
env->v7m.secure);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -6480,7 +6486,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
return;
|
||||
}
|
||||
}
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG);
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
|
||||
break;
|
||||
case EXCP_IRQ:
|
||||
break;
|
||||
|
@ -8892,12 +8898,68 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
|||
break;
|
||||
case 20: /* CONTROL */
|
||||
return env->v7m.control[env->v7m.secure];
|
||||
case 0x94: /* CONTROL_NS */
|
||||
/* We have to handle this here because unprivileged Secure code
|
||||
* can read the NS CONTROL register.
|
||||
*/
|
||||
if (!env->v7m.secure) {
|
||||
return 0;
|
||||
}
|
||||
return env->v7m.control[M_REG_NS];
|
||||
}
|
||||
|
||||
if (el == 0) {
|
||||
return 0; /* unprivileged reads others as zero */
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
switch (reg) {
|
||||
case 0x88: /* MSP_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return 0;
|
||||
}
|
||||
return env->v7m.other_ss_msp;
|
||||
case 0x89: /* PSP_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return 0;
|
||||
}
|
||||
return env->v7m.other_ss_psp;
|
||||
case 0x90: /* PRIMASK_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return 0;
|
||||
}
|
||||
return env->v7m.primask[M_REG_NS];
|
||||
case 0x91: /* BASEPRI_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return 0;
|
||||
}
|
||||
return env->v7m.basepri[M_REG_NS];
|
||||
case 0x93: /* FAULTMASK_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return 0;
|
||||
}
|
||||
return env->v7m.faultmask[M_REG_NS];
|
||||
case 0x98: /* SP_NS */
|
||||
{
|
||||
/* This gives the non-secure SP selected based on whether we're
|
||||
* currently in handler mode or not, using the NS CONTROL.SPSEL.
|
||||
*/
|
||||
bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
|
||||
|
||||
if (!env->v7m.secure) {
|
||||
return 0;
|
||||
}
|
||||
if (!arm_v7m_is_handler_mode(env) && spsel) {
|
||||
return env->v7m.other_ss_psp;
|
||||
} else {
|
||||
return env->v7m.other_ss_msp;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case 8: /* MSP */
|
||||
return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ?
|
||||
|
@ -8936,6 +8998,60 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
|||
return;
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
switch (reg) {
|
||||
case 0x88: /* MSP_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return;
|
||||
}
|
||||
env->v7m.other_ss_msp = val;
|
||||
return;
|
||||
case 0x89: /* PSP_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return;
|
||||
}
|
||||
env->v7m.other_ss_psp = val;
|
||||
return;
|
||||
case 0x90: /* PRIMASK_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return;
|
||||
}
|
||||
env->v7m.primask[M_REG_NS] = val & 1;
|
||||
return;
|
||||
case 0x91: /* BASEPRI_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return;
|
||||
}
|
||||
env->v7m.basepri[M_REG_NS] = val & 0xff;
|
||||
return;
|
||||
case 0x93: /* FAULTMASK_NS */
|
||||
if (!env->v7m.secure) {
|
||||
return;
|
||||
}
|
||||
env->v7m.faultmask[M_REG_NS] = val & 1;
|
||||
return;
|
||||
case 0x98: /* SP_NS */
|
||||
{
|
||||
/* This gives the non-secure SP selected based on whether we're
|
||||
* currently in handler mode or not, using the NS CONTROL.SPSEL.
|
||||
*/
|
||||
bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
|
||||
|
||||
if (!env->v7m.secure) {
|
||||
return;
|
||||
}
|
||||
if (!arm_v7m_is_handler_mode(env) && spsel) {
|
||||
env->v7m.other_ss_psp = val;
|
||||
} else {
|
||||
env->v7m.other_ss_msp = val;
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case 0 ... 7: /* xPSR sub-fields */
|
||||
/* only APSR is actually writable */
|
||||
|
|
|
@ -1203,12 +1203,14 @@ static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table,
|
|||
}
|
||||
|
||||
/*
|
||||
* the instruction disassembly implemented here matches
|
||||
* the instruction encoding classifications in chapter 3 (C3)
|
||||
* of the ARM Architecture Reference Manual (DDI0487A_a)
|
||||
* The instruction disassembly implemented here matches
|
||||
* the instruction encoding classifications in chapter C4
|
||||
* of the ARM Architecture Reference Manual (DDI0487B_a);
|
||||
* classification names and decode diagrams here should generally
|
||||
* match up with those in the manual.
|
||||
*/
|
||||
|
||||
/* C3.2.7 Unconditional branch (immediate)
|
||||
/* Unconditional branch (immediate)
|
||||
* 31 30 26 25 0
|
||||
* +----+-----------+-------------------------------------+
|
||||
* | op | 0 0 1 0 1 | imm26 |
|
||||
|
@ -1219,15 +1221,15 @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
|
|||
uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
|
||||
|
||||
if (insn & (1U << 31)) {
|
||||
/* C5.6.26 BL Branch with link */
|
||||
/* BL Branch with link */
|
||||
tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
|
||||
}
|
||||
|
||||
/* C5.6.20 B Branch / C5.6.26 BL Branch with link */
|
||||
/* B Branch / BL Branch with link */
|
||||
gen_goto_tb(s, 0, addr);
|
||||
}
|
||||
|
||||
/* C3.2.1 Compare & branch (immediate)
|
||||
/* Compare and branch (immediate)
|
||||
* 31 30 25 24 23 5 4 0
|
||||
* +----+-------------+----+---------------------+--------+
|
||||
* | sf | 0 1 1 0 1 0 | op | imm19 | Rt |
|
||||
|
@ -1256,7 +1258,7 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
|
|||
gen_goto_tb(s, 1, addr);
|
||||
}
|
||||
|
||||
/* C3.2.5 Test & branch (immediate)
|
||||
/* Test and branch (immediate)
|
||||
* 31 30 25 24 23 19 18 5 4 0
|
||||
* +----+-------------+----+-------+-------------+------+
|
||||
* | b5 | 0 1 1 0 1 1 | op | b40 | imm14 | Rt |
|
||||
|
@ -1285,7 +1287,7 @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
|
|||
gen_goto_tb(s, 1, addr);
|
||||
}
|
||||
|
||||
/* C3.2.2 / C5.6.19 Conditional branch (immediate)
|
||||
/* Conditional branch (immediate)
|
||||
* 31 25 24 23 5 4 3 0
|
||||
* +---------------+----+---------------------+----+------+
|
||||
* | 0 1 0 1 0 1 0 | o1 | imm19 | o0 | cond |
|
||||
|
@ -1316,7 +1318,7 @@ static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C5.6.68 HINT */
|
||||
/* HINT instruction group, including various allocated HINTs */
|
||||
static void handle_hint(DisasContext *s, uint32_t insn,
|
||||
unsigned int op1, unsigned int op2, unsigned int crm)
|
||||
{
|
||||
|
@ -1401,7 +1403,7 @@ static void handle_sync(DisasContext *s, uint32_t insn,
|
|||
}
|
||||
}
|
||||
|
||||
/* C5.6.130 MSR (immediate) - move immediate to processor state field */
|
||||
/* MSR (immediate) - move immediate to processor state field */
|
||||
static void handle_msr_i(DisasContext *s, uint32_t insn,
|
||||
unsigned int op1, unsigned int op2, unsigned int crm)
|
||||
{
|
||||
|
@ -1477,10 +1479,10 @@ static void gen_set_nzcv(TCGv_i64 tcg_rt)
|
|||
tcg_temp_free_i32(nzcv);
|
||||
}
|
||||
|
||||
/* C5.6.129 MRS - move from system register
|
||||
* C5.6.131 MSR (register) - move to system register
|
||||
* C5.6.204 SYS
|
||||
* C5.6.205 SYSL
|
||||
/* MRS - move from system register
|
||||
* MSR (register) - move to system register
|
||||
* SYS
|
||||
* SYSL
|
||||
* These are all essentially the same insn in 'read' and 'write'
|
||||
* versions, with varying op0 fields.
|
||||
*/
|
||||
|
@ -1603,7 +1605,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.2.4 System
|
||||
/* System
|
||||
* 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
|
||||
* +---------------------+---+-----+-----+-------+-------+-----+------+
|
||||
* | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 | CRn | CRm | op2 | Rt |
|
||||
|
@ -1626,13 +1628,13 @@ static void disas_system(DisasContext *s, uint32_t insn)
|
|||
return;
|
||||
}
|
||||
switch (crn) {
|
||||
case 2: /* C5.6.68 HINT */
|
||||
case 2: /* HINT (including allocated hints like NOP, YIELD, etc) */
|
||||
handle_hint(s, insn, op1, op2, crm);
|
||||
break;
|
||||
case 3: /* CLREX, DSB, DMB, ISB */
|
||||
handle_sync(s, insn, op1, op2, crm);
|
||||
break;
|
||||
case 4: /* C5.6.130 MSR (immediate) */
|
||||
case 4: /* MSR (immediate) */
|
||||
handle_msr_i(s, insn, op1, op2, crm);
|
||||
break;
|
||||
default:
|
||||
|
@ -1644,7 +1646,7 @@ static void disas_system(DisasContext *s, uint32_t insn)
|
|||
handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
|
||||
}
|
||||
|
||||
/* C3.2.3 Exception generation
|
||||
/* Exception generation
|
||||
*
|
||||
* 31 24 23 21 20 5 4 2 1 0
|
||||
* +-----------------+-----+------------------------+-----+----+
|
||||
|
@ -1751,7 +1753,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.2.7 Unconditional branch (register)
|
||||
/* Unconditional branch (register)
|
||||
* 31 25 24 21 20 16 15 10 9 5 4 0
|
||||
* +---------------+-------+-------+-------+------+-------+
|
||||
* | 1 1 0 1 0 1 1 | opc | op2 | op3 | Rn | op4 |
|
||||
|
@ -1806,7 +1808,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
|||
s->base.is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
/* C3.2 Branches, exception generating and system instructions */
|
||||
/* Branches, exception generating and system instructions */
|
||||
static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
switch (extract32(insn, 25, 7)) {
|
||||
|
@ -1966,7 +1968,7 @@ static bool disas_ldst_compute_iss_sf(int size, bool is_signed, int opc)
|
|||
return regsize == 64;
|
||||
}
|
||||
|
||||
/* C3.3.6 Load/store exclusive
|
||||
/* Load/store exclusive
|
||||
*
|
||||
* 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0
|
||||
* +-----+-------------+----+---+----+------+----+-------+------+------+
|
||||
|
@ -2043,7 +2045,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
|
||||
/*
|
||||
* C3.3.5 Load register (literal)
|
||||
* Load register (literal)
|
||||
*
|
||||
* 31 30 29 27 26 25 24 23 5 4 0
|
||||
* +-----+-------+---+-----+-------------------+-------+
|
||||
|
@ -2099,15 +2101,15 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
|
||||
/*
|
||||
* C5.6.80 LDNP (Load Pair - non-temporal hint)
|
||||
* C5.6.81 LDP (Load Pair - non vector)
|
||||
* C5.6.82 LDPSW (Load Pair Signed Word - non vector)
|
||||
* C5.6.176 STNP (Store Pair - non-temporal hint)
|
||||
* C5.6.177 STP (Store Pair - non vector)
|
||||
* C6.3.165 LDNP (Load Pair of SIMD&FP - non-temporal hint)
|
||||
* C6.3.165 LDP (Load Pair of SIMD&FP)
|
||||
* C6.3.284 STNP (Store Pair of SIMD&FP - non-temporal hint)
|
||||
* C6.3.284 STP (Store Pair of SIMD&FP)
|
||||
* LDNP (Load Pair - non-temporal hint)
|
||||
* LDP (Load Pair - non vector)
|
||||
* LDPSW (Load Pair Signed Word - non vector)
|
||||
* STNP (Store Pair - non-temporal hint)
|
||||
* STP (Store Pair - non vector)
|
||||
* LDNP (Load Pair of SIMD&FP - non-temporal hint)
|
||||
* LDP (Load Pair of SIMD&FP)
|
||||
* STNP (Store Pair of SIMD&FP - non-temporal hint)
|
||||
* STP (Store Pair of SIMD&FP)
|
||||
*
|
||||
* 31 30 29 27 26 25 24 23 22 21 15 14 10 9 5 4 0
|
||||
* +-----+-------+---+---+-------+---+-----------------------------+
|
||||
|
@ -2253,9 +2255,9 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
|
||||
/*
|
||||
* C3.3.8 Load/store (immediate post-indexed)
|
||||
* C3.3.9 Load/store (immediate pre-indexed)
|
||||
* C3.3.12 Load/store (unscaled immediate)
|
||||
* Load/store (immediate post-indexed)
|
||||
* Load/store (immediate pre-indexed)
|
||||
* Load/store (unscaled immediate)
|
||||
*
|
||||
* 31 30 29 27 26 25 24 23 22 21 20 12 11 10 9 5 4 0
|
||||
* +----+-------+---+-----+-----+---+--------+-----+------+------+
|
||||
|
@ -2371,7 +2373,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
|
|||
}
|
||||
|
||||
/*
|
||||
* C3.3.10 Load/store (register offset)
|
||||
* Load/store (register offset)
|
||||
*
|
||||
* 31 30 29 27 26 25 24 23 22 21 20 16 15 13 12 11 10 9 5 4 0
|
||||
* +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
|
||||
|
@ -2468,7 +2470,7 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
|
|||
}
|
||||
|
||||
/*
|
||||
* C3.3.13 Load/store (unsigned immediate)
|
||||
* Load/store (unsigned immediate)
|
||||
*
|
||||
* 31 30 29 27 26 25 24 23 22 21 10 9 5
|
||||
* +----+-------+---+-----+-----+------------+-------+------+
|
||||
|
@ -2579,14 +2581,14 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.3.1 AdvSIMD load/store multiple structures
|
||||
/* AdvSIMD load/store multiple structures
|
||||
*
|
||||
* 31 30 29 23 22 21 16 15 12 11 10 9 5 4 0
|
||||
* +---+---+---------------+---+-------------+--------+------+------+------+
|
||||
* | 0 | Q | 0 0 1 1 0 0 0 | L | 0 0 0 0 0 0 | opcode | size | Rn | Rt |
|
||||
* +---+---+---------------+---+-------------+--------+------+------+------+
|
||||
*
|
||||
* C3.3.2 AdvSIMD load/store multiple structures (post-indexed)
|
||||
* AdvSIMD load/store multiple structures (post-indexed)
|
||||
*
|
||||
* 31 30 29 23 22 21 20 16 15 12 11 10 9 5 4 0
|
||||
* +---+---+---------------+---+---+---------+--------+------+------+------+
|
||||
|
@ -2711,14 +2713,14 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(tcg_addr);
|
||||
}
|
||||
|
||||
/* C3.3.3 AdvSIMD load/store single structure
|
||||
/* AdvSIMD load/store single structure
|
||||
*
|
||||
* 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0
|
||||
* +---+---+---------------+-----+-----------+-----+---+------+------+------+
|
||||
* | 0 | Q | 0 0 1 1 0 1 0 | L R | 0 0 0 0 0 | opc | S | size | Rn | Rt |
|
||||
* +---+---+---------------+-----+-----------+-----+---+------+------+------+
|
||||
*
|
||||
* C3.3.4 AdvSIMD load/store single structure (post-indexed)
|
||||
* AdvSIMD load/store single structure (post-indexed)
|
||||
*
|
||||
* 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0
|
||||
* +---+---+---------------+-----+-----------+-----+---+------+------+------+
|
||||
|
@ -2861,7 +2863,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(tcg_addr);
|
||||
}
|
||||
|
||||
/* C3.3 Loads and stores */
|
||||
/* Loads and stores */
|
||||
static void disas_ldst(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
switch (extract32(insn, 24, 6)) {
|
||||
|
@ -2891,7 +2893,7 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.4.6 PC-rel. addressing
|
||||
/* PC-rel. addressing
|
||||
* 31 30 29 28 24 23 5 4 0
|
||||
* +----+-------+-----------+-------------------+------+
|
||||
* | op | immlo | 1 0 0 0 0 | immhi | Rd |
|
||||
|
@ -2920,7 +2922,7 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
|
||||
/*
|
||||
* C3.4.1 Add/subtract (immediate)
|
||||
* Add/subtract (immediate)
|
||||
*
|
||||
* 31 30 29 28 24 23 22 21 10 9 5 4 0
|
||||
* +--+--+--+-----------+-----+-------------+-----+-----+
|
||||
|
@ -3070,7 +3072,7 @@ static bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* C3.4.4 Logical (immediate)
|
||||
/* Logical (immediate)
|
||||
* 31 30 29 28 23 22 21 16 15 10 9 5 4 0
|
||||
* +----+-----+-------------+---+------+------+------+------+
|
||||
* | sf | opc | 1 0 0 1 0 0 | N | immr | imms | Rn | Rd |
|
||||
|
@ -3143,7 +3145,7 @@ static void disas_logic_imm(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
|
||||
/*
|
||||
* C3.4.5 Move wide (immediate)
|
||||
* Move wide (immediate)
|
||||
*
|
||||
* 31 30 29 28 23 22 21 20 5 4 0
|
||||
* +--+-----+-------------+-----+----------------+------+
|
||||
|
@ -3195,7 +3197,7 @@ static void disas_movw_imm(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.4.2 Bitfield
|
||||
/* Bitfield
|
||||
* 31 30 29 28 23 22 21 16 15 10 9 5 4 0
|
||||
* +----+-----+-------------+---+------+------+------+------+
|
||||
* | sf | opc | 1 0 0 1 1 0 | N | immr | imms | Rn | Rd |
|
||||
|
@ -3273,7 +3275,7 @@ static void disas_bitfield(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.4.3 Extract
|
||||
/* Extract
|
||||
* 31 30 29 28 23 22 21 20 16 15 10 9 5 4 0
|
||||
* +----+------+-------------+---+----+------+--------+------+------+
|
||||
* | sf | op21 | 1 0 0 1 1 1 | N | o0 | Rm | imms | Rn | Rd |
|
||||
|
@ -3333,7 +3335,7 @@ static void disas_extract(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.4 Data processing - immediate */
|
||||
/* Data processing - immediate */
|
||||
static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
switch (extract32(insn, 23, 6)) {
|
||||
|
@ -3427,7 +3429,7 @@ static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf,
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.5.10 Logical (shifted register)
|
||||
/* Logical (shifted register)
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
|
||||
* +----+-----+-----------+-------+---+------+--------+------+------+
|
||||
* | sf | opc | 0 1 0 1 0 | shift | N | Rm | imm6 | Rn | Rd |
|
||||
|
@ -3518,7 +3520,7 @@ static void disas_logic_reg(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
|
||||
/*
|
||||
* C3.5.1 Add/subtract (extended register)
|
||||
* Add/subtract (extended register)
|
||||
*
|
||||
* 31|30|29|28 24|23 22|21|20 16|15 13|12 10|9 5|4 0|
|
||||
* +--+--+--+-----------+-----+--+-------+------+------+----+----+
|
||||
|
@ -3591,7 +3593,7 @@ static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
|
||||
/*
|
||||
* C3.5.2 Add/subtract (shifted register)
|
||||
* Add/subtract (shifted register)
|
||||
*
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
|
||||
* +--+--+--+-----------+-----+--+-------+---------+------+------+
|
||||
|
@ -3654,13 +3656,12 @@ static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(tcg_result);
|
||||
}
|
||||
|
||||
/* C3.5.9 Data-processing (3 source)
|
||||
|
||||
31 30 29 28 24 23 21 20 16 15 14 10 9 5 4 0
|
||||
+--+------+-----------+------+------+----+------+------+------+
|
||||
|sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd |
|
||||
+--+------+-----------+------+------+----+------+------+------+
|
||||
|
||||
/* Data-processing (3 source)
|
||||
*
|
||||
* 31 30 29 28 24 23 21 20 16 15 14 10 9 5 4 0
|
||||
* +--+------+-----------+------+------+----+------+------+------+
|
||||
* |sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd |
|
||||
* +--+------+-----------+------+------+----+------+------+------+
|
||||
*/
|
||||
static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
|
@ -3753,7 +3754,7 @@ static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(tcg_tmp);
|
||||
}
|
||||
|
||||
/* C3.5.3 - Add/subtract (with carry)
|
||||
/* Add/subtract (with carry)
|
||||
* 31 30 29 28 27 26 25 24 23 22 21 20 16 15 10 9 5 4 0
|
||||
* +--+--+--+------------------------+------+---------+------+-----+
|
||||
* |sf|op| S| 1 1 0 1 0 0 0 0 | rm | opcode2 | Rn | Rd |
|
||||
|
@ -3795,7 +3796,7 @@ static void disas_adc_sbc(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.5.4 - C3.5.5 Conditional compare (immediate / register)
|
||||
/* Conditional compare (immediate / register)
|
||||
* 31 30 29 28 27 26 25 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
|
||||
* +--+--+--+------------------------+--------+------+----+--+------+--+-----+
|
||||
* |sf|op| S| 1 1 0 1 0 0 1 0 |imm5/rm | cond |i/r |o2| Rn |o3|nzcv |
|
||||
|
@ -3900,7 +3901,7 @@ static void disas_cc(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i32(tcg_t2);
|
||||
}
|
||||
|
||||
/* C3.5.6 Conditional select
|
||||
/* Conditional select
|
||||
* 31 30 29 28 21 20 16 15 12 11 10 9 5 4 0
|
||||
* +----+----+---+-----------------+------+------+-----+------+------+
|
||||
* | sf | op | S | 1 1 0 1 0 1 0 0 | Rm | cond | op2 | Rn | Rd |
|
||||
|
@ -4011,7 +4012,7 @@ static void handle_rbit(DisasContext *s, unsigned int sf,
|
|||
}
|
||||
}
|
||||
|
||||
/* C5.6.149 REV with sf==1, opcode==3 ("REV64") */
|
||||
/* REV with sf==1, opcode==3 ("REV64") */
|
||||
static void handle_rev64(DisasContext *s, unsigned int sf,
|
||||
unsigned int rn, unsigned int rd)
|
||||
{
|
||||
|
@ -4022,8 +4023,8 @@ static void handle_rev64(DisasContext *s, unsigned int sf,
|
|||
tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn));
|
||||
}
|
||||
|
||||
/* C5.6.149 REV with sf==0, opcode==2
|
||||
* C5.6.151 REV32 (sf==1, opcode==2)
|
||||
/* REV with sf==0, opcode==2
|
||||
* REV32 (sf==1, opcode==2)
|
||||
*/
|
||||
static void handle_rev32(DisasContext *s, unsigned int sf,
|
||||
unsigned int rn, unsigned int rd)
|
||||
|
@ -4048,7 +4049,7 @@ static void handle_rev32(DisasContext *s, unsigned int sf,
|
|||
}
|
||||
}
|
||||
|
||||
/* C5.6.150 REV16 (opcode==1) */
|
||||
/* REV16 (opcode==1) */
|
||||
static void handle_rev16(DisasContext *s, unsigned int sf,
|
||||
unsigned int rn, unsigned int rd)
|
||||
{
|
||||
|
@ -4067,7 +4068,7 @@ static void handle_rev16(DisasContext *s, unsigned int sf,
|
|||
tcg_temp_free_i64(tcg_tmp);
|
||||
}
|
||||
|
||||
/* C3.5.7 Data-processing (1 source)
|
||||
/* Data-processing (1 source)
|
||||
* 31 30 29 28 21 20 16 15 10 9 5 4 0
|
||||
* +----+---+---+-----------------+---------+--------+------+------+
|
||||
* | sf | 1 | S | 1 1 0 1 0 1 1 0 | opcode2 | opcode | Rn | Rd |
|
||||
|
@ -4136,7 +4137,7 @@ static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
|
|||
}
|
||||
}
|
||||
|
||||
/* C5.6.115 LSLV, C5.6.118 LSRV, C5.6.17 ASRV, C5.6.154 RORV */
|
||||
/* LSLV, LSRV, ASRV, RORV */
|
||||
static void handle_shift_reg(DisasContext *s,
|
||||
enum a64_shift_type shift_type, unsigned int sf,
|
||||
unsigned int rm, unsigned int rn, unsigned int rd)
|
||||
|
@ -4198,7 +4199,7 @@ static void handle_crc32(DisasContext *s,
|
|||
tcg_temp_free_i32(tcg_bytes);
|
||||
}
|
||||
|
||||
/* C3.5.8 Data-processing (2 source)
|
||||
/* Data-processing (2 source)
|
||||
* 31 30 29 28 21 20 16 15 10 9 5 4 0
|
||||
* +----+---+---+-----------------+------+--------+------+------+
|
||||
* | sf | 0 | S | 1 1 0 1 0 1 1 0 | Rm | opcode | Rn | Rd |
|
||||
|
@ -4257,7 +4258,7 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.5 Data processing - register */
|
||||
/* Data processing - register */
|
||||
static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
switch (extract32(insn, 24, 5)) {
|
||||
|
@ -4351,7 +4352,7 @@ static void handle_fp_compare(DisasContext *s, bool is_double,
|
|||
tcg_temp_free_i64(tcg_flags);
|
||||
}
|
||||
|
||||
/* C3.6.22 Floating point compare
|
||||
/* Floating point compare
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 14 13 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+------+-----+---------+------+-------+
|
||||
* | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | op | 1 0 0 0 | Rn | op2 |
|
||||
|
@ -4381,7 +4382,7 @@ static void disas_fp_compare(DisasContext *s, uint32_t insn)
|
|||
handle_fp_compare(s, type, rn, rm, opc & 1, opc & 2);
|
||||
}
|
||||
|
||||
/* C3.6.23 Floating point conditional compare
|
||||
/* Floating point conditional compare
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
|
||||
* +---+---+---+-----------+------+---+------+------+-----+------+----+------+
|
||||
* | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 0 1 | Rn | op | nzcv |
|
||||
|
@ -4429,7 +4430,7 @@ static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.24 Floating point conditional select
|
||||
/* Floating point conditional select
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+------+------+-----+------+------+
|
||||
* | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 1 1 | Rn | Rd |
|
||||
|
@ -4476,7 +4477,7 @@ static void disas_fp_csel(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(t_true);
|
||||
}
|
||||
|
||||
/* C3.6.25 Floating-point data-processing (1 source) - single precision */
|
||||
/* Floating-point data-processing (1 source) - single precision */
|
||||
static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
|
||||
{
|
||||
TCGv_ptr fpst;
|
||||
|
@ -4532,7 +4533,7 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
|
|||
tcg_temp_free_i32(tcg_res);
|
||||
}
|
||||
|
||||
/* C3.6.25 Floating-point data-processing (1 source) - double precision */
|
||||
/* Floating-point data-processing (1 source) - double precision */
|
||||
static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
|
||||
{
|
||||
TCGv_ptr fpst;
|
||||
|
@ -4654,7 +4655,7 @@ static void handle_fp_fcvt(DisasContext *s, int opcode,
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.25 Floating point data-processing (1 source)
|
||||
/* Floating point data-processing (1 source)
|
||||
* 31 30 29 28 24 23 22 21 20 15 14 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+--------+-----------+------+------+
|
||||
* | M | 0 | S | 1 1 1 1 0 | type | 1 | opcode | 1 0 0 0 0 | Rn | Rd |
|
||||
|
@ -4712,7 +4713,7 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.26 Floating-point data-processing (2 source) - single precision */
|
||||
/* Floating-point data-processing (2 source) - single precision */
|
||||
static void handle_fp_2src_single(DisasContext *s, int opcode,
|
||||
int rd, int rn, int rm)
|
||||
{
|
||||
|
@ -4765,7 +4766,7 @@ static void handle_fp_2src_single(DisasContext *s, int opcode,
|
|||
tcg_temp_free_i32(tcg_res);
|
||||
}
|
||||
|
||||
/* C3.6.26 Floating-point data-processing (2 source) - double precision */
|
||||
/* Floating-point data-processing (2 source) - double precision */
|
||||
static void handle_fp_2src_double(DisasContext *s, int opcode,
|
||||
int rd, int rn, int rm)
|
||||
{
|
||||
|
@ -4818,7 +4819,7 @@ static void handle_fp_2src_double(DisasContext *s, int opcode,
|
|||
tcg_temp_free_i64(tcg_res);
|
||||
}
|
||||
|
||||
/* C3.6.26 Floating point data-processing (2 source)
|
||||
/* Floating point data-processing (2 source)
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+------+--------+-----+------+------+
|
||||
* | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | opcode | 1 0 | Rn | Rd |
|
||||
|
@ -4855,7 +4856,7 @@ static void disas_fp_2src(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.27 Floating-point data-processing (3 source) - single precision */
|
||||
/* Floating-point data-processing (3 source) - single precision */
|
||||
static void handle_fp_3src_single(DisasContext *s, bool o0, bool o1,
|
||||
int rd, int rn, int rm, int ra)
|
||||
{
|
||||
|
@ -4893,7 +4894,7 @@ static void handle_fp_3src_single(DisasContext *s, bool o0, bool o1,
|
|||
tcg_temp_free_i32(tcg_res);
|
||||
}
|
||||
|
||||
/* C3.6.27 Floating-point data-processing (3 source) - double precision */
|
||||
/* Floating-point data-processing (3 source) - double precision */
|
||||
static void handle_fp_3src_double(DisasContext *s, bool o0, bool o1,
|
||||
int rd, int rn, int rm, int ra)
|
||||
{
|
||||
|
@ -4931,7 +4932,7 @@ static void handle_fp_3src_double(DisasContext *s, bool o0, bool o1,
|
|||
tcg_temp_free_i64(tcg_res);
|
||||
}
|
||||
|
||||
/* C3.6.27 Floating point data-processing (3 source)
|
||||
/* Floating point data-processing (3 source)
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 14 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+----+------+----+------+------+------+
|
||||
* | M | 0 | S | 1 1 1 1 1 | type | o1 | Rm | o0 | Ra | Rn | Rd |
|
||||
|
@ -4965,7 +4966,7 @@ static void disas_fp_3src(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.28 Floating point immediate
|
||||
/* Floating point immediate
|
||||
* 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+------------+-------+------+------+
|
||||
* | M | 0 | S | 1 1 1 1 0 | type | 1 | imm8 | 1 0 0 | imm5 | Rd |
|
||||
|
@ -5136,7 +5137,7 @@ static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode,
|
|||
tcg_temp_free_i32(tcg_shift);
|
||||
}
|
||||
|
||||
/* C3.6.29 Floating point <-> fixed point conversions
|
||||
/* Floating point <-> fixed point conversions
|
||||
* 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
|
||||
* +----+---+---+-----------+------+---+-------+--------+-------+------+------+
|
||||
* | sf | 0 | S | 1 1 1 1 0 | type | 0 | rmode | opcode | scale | Rn | Rd |
|
||||
|
@ -5236,7 +5237,7 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.30 Floating point <-> integer conversions
|
||||
/* Floating point <-> integer conversions
|
||||
* 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
|
||||
* +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
|
||||
* | sf | 0 | S | 1 1 1 1 0 | type | 1 | rmode | opc | 0 0 0 0 0 0 | Rn | Rd |
|
||||
|
@ -5371,7 +5372,7 @@ static void do_ext64(DisasContext *s, TCGv_i64 tcg_left, TCGv_i64 tcg_right,
|
|||
tcg_temp_free_i64(tcg_tmp);
|
||||
}
|
||||
|
||||
/* C3.6.1 EXT
|
||||
/* EXT
|
||||
* 31 30 29 24 23 22 21 20 16 15 14 11 10 9 5 4 0
|
||||
* +---+---+-------------+-----+---+------+---+------+---+------+------+
|
||||
* | 0 | Q | 1 0 1 1 1 0 | op2 | 0 | Rm | 0 | imm4 | 0 | Rn | Rd |
|
||||
|
@ -5444,7 +5445,7 @@ static void disas_simd_ext(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(tcg_resh);
|
||||
}
|
||||
|
||||
/* C3.6.2 TBL/TBX
|
||||
/* TBL/TBX
|
||||
* 31 30 29 24 23 22 21 20 16 15 14 13 12 11 10 9 5 4 0
|
||||
* +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
|
||||
* | 0 | Q | 0 0 1 1 1 0 | op2 | 0 | Rm | 0 | len | op | 0 0 | Rn | Rd |
|
||||
|
@ -5512,7 +5513,7 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(tcg_resh);
|
||||
}
|
||||
|
||||
/* C3.6.3 ZIP/UZP/TRN
|
||||
/* ZIP/UZP/TRN
|
||||
* 31 30 29 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0
|
||||
* +---+---+-------------+------+---+------+---+------------------+------+
|
||||
* | 0 | Q | 0 0 1 1 1 0 | size | 0 | Rm | 0 | opc | 1 0 | Rn | Rd |
|
||||
|
@ -5624,7 +5625,7 @@ static void do_minmaxop(DisasContext *s, TCGv_i32 tcg_elt1, TCGv_i32 tcg_elt2,
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.4 AdvSIMD across lanes
|
||||
/* AdvSIMD across lanes
|
||||
* 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+-----------+--------+-----+------+------+
|
||||
* | 0 | Q | U | 0 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd |
|
||||
|
@ -5791,7 +5792,7 @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(tcg_res);
|
||||
}
|
||||
|
||||
/* C6.3.31 DUP (Element, Vector)
|
||||
/* DUP (Element, Vector)
|
||||
*
|
||||
* 31 30 29 21 20 16 15 10 9 5 4 0
|
||||
* +---+---+-------------------+--------+-------------+------+------+
|
||||
|
@ -5834,7 +5835,7 @@ static void handle_simd_dupe(DisasContext *s, int is_q, int rd, int rn,
|
|||
tcg_temp_free_i64(tmp);
|
||||
}
|
||||
|
||||
/* C6.3.31 DUP (element, scalar)
|
||||
/* DUP (element, scalar)
|
||||
* 31 21 20 16 15 10 9 5 4 0
|
||||
* +-----------------------+--------+-------------+------+------+
|
||||
* | 0 1 0 1 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 0 1 | Rn | Rd |
|
||||
|
@ -5867,7 +5868,7 @@ static void handle_simd_dupes(DisasContext *s, int rd, int rn,
|
|||
tcg_temp_free_i64(tmp);
|
||||
}
|
||||
|
||||
/* C6.3.32 DUP (General)
|
||||
/* DUP (General)
|
||||
*
|
||||
* 31 30 29 21 20 16 15 10 9 5 4 0
|
||||
* +---+---+-------------------+--------+-------------+------+------+
|
||||
|
@ -5901,7 +5902,7 @@ static void handle_simd_dupg(DisasContext *s, int is_q, int rd, int rn,
|
|||
}
|
||||
}
|
||||
|
||||
/* C6.3.150 INS (Element)
|
||||
/* INS (Element)
|
||||
*
|
||||
* 31 21 20 16 15 14 11 10 9 5 4 0
|
||||
* +-----------------------+--------+------------+---+------+------+
|
||||
|
@ -5939,7 +5940,7 @@ static void handle_simd_inse(DisasContext *s, int rd, int rn,
|
|||
}
|
||||
|
||||
|
||||
/* C6.3.151 INS (General)
|
||||
/* INS (General)
|
||||
*
|
||||
* 31 21 20 16 15 10 9 5 4 0
|
||||
* +-----------------------+--------+-------------+------+------+
|
||||
|
@ -5968,8 +5969,8 @@ static void handle_simd_insg(DisasContext *s, int rd, int rn, int imm5)
|
|||
}
|
||||
|
||||
/*
|
||||
* C6.3.321 UMOV (General)
|
||||
* C6.3.237 SMOV (General)
|
||||
* UMOV (General)
|
||||
* SMOV (General)
|
||||
*
|
||||
* 31 30 29 21 20 16 15 12 10 9 5 4 0
|
||||
* +---+---+-------------------+--------+-------------+------+------+
|
||||
|
@ -6014,7 +6015,7 @@ static void handle_simd_umov_smov(DisasContext *s, int is_q, int is_signed,
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.5 AdvSIMD copy
|
||||
/* AdvSIMD copy
|
||||
* 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0
|
||||
* +---+---+----+-----------------+------+---+------+---+------+------+
|
||||
* | 0 | Q | op | 0 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
|
||||
|
@ -6066,7 +6067,7 @@ static void disas_simd_copy(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.6 AdvSIMD modified immediate
|
||||
/* AdvSIMD modified immediate
|
||||
* 31 30 29 28 19 18 16 15 12 11 10 9 5 4 0
|
||||
* +---+---+----+---------------------+-----+-------+----+---+-------+------+
|
||||
* | 0 | Q | op | 0 1 1 1 1 0 0 0 0 0 | abc | cmode | o2 | 1 | defgh | Rd |
|
||||
|
@ -6199,7 +6200,7 @@ static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i64(tcg_imm);
|
||||
}
|
||||
|
||||
/* C3.6.7 AdvSIMD scalar copy
|
||||
/* AdvSIMD scalar copy
|
||||
* 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0
|
||||
* +-----+----+-----------------+------+---+------+---+------+------+
|
||||
* | 0 1 | op | 1 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
|
||||
|
@ -6222,7 +6223,7 @@ static void disas_simd_scalar_copy(DisasContext *s, uint32_t insn)
|
|||
handle_simd_dupes(s, rd, rn, imm5);
|
||||
}
|
||||
|
||||
/* C3.6.8 AdvSIMD scalar pairwise
|
||||
/* AdvSIMD scalar pairwise
|
||||
* 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
|
||||
* +-----+---+-----------+------+-----------+--------+-----+------+------+
|
||||
* | 0 1 | U | 1 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd |
|
||||
|
@ -6948,7 +6949,7 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
|
|||
tcg_temp_free_i32(tcg_rmode);
|
||||
}
|
||||
|
||||
/* C3.6.9 AdvSIMD scalar shift by immediate
|
||||
/* AdvSIMD scalar shift by immediate
|
||||
* 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
|
||||
* +-----+---+-------------+------+------+--------+---+------+------+
|
||||
* | 0 1 | U | 1 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd |
|
||||
|
@ -7023,7 +7024,7 @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.10 AdvSIMD scalar three different
|
||||
/* AdvSIMD scalar three different
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
|
||||
* +-----+---+-----------+------+---+------+--------+-----+------+------+
|
||||
* | 0 1 | U | 1 1 1 1 0 | size | 1 | Rm | opcode | 0 0 | Rn | Rd |
|
||||
|
@ -7410,7 +7411,7 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.11 AdvSIMD scalar three same
|
||||
/* AdvSIMD scalar three same
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 11 10 9 5 4 0
|
||||
* +-----+---+-----------+------+---+------+--------+---+------+------+
|
||||
* | 0 1 | U | 1 1 1 1 0 | size | 1 | Rm | opcode | 1 | Rn | Rd |
|
||||
|
@ -8079,7 +8080,7 @@ static void handle_2misc_satacc(DisasContext *s, bool is_scalar, bool is_u,
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.12 AdvSIMD scalar two reg misc
|
||||
/* AdvSIMD scalar two reg misc
|
||||
* 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
|
||||
* +-----+---+-----------+------+-----------+--------+-----+------+------+
|
||||
* | 0 1 | U | 1 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd |
|
||||
|
@ -8507,7 +8508,7 @@ static void handle_vec_simd_shrn(DisasContext *s, bool is_q,
|
|||
}
|
||||
|
||||
|
||||
/* C3.6.14 AdvSIMD shift by immediate
|
||||
/* AdvSIMD shift by immediate
|
||||
* 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
|
||||
* +---+---+---+-------------+------+------+--------+---+------+------+
|
||||
* | 0 | Q | U | 0 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd |
|
||||
|
@ -8926,7 +8927,7 @@ static void handle_pmull_64(DisasContext *s, int is_q, int rd, int rn, int rm)
|
|||
tcg_temp_free_i64(tcg_res);
|
||||
}
|
||||
|
||||
/* C3.6.15 AdvSIMD three different
|
||||
/* AdvSIMD three different
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+------+--------+-----+------+------+
|
||||
* | 0 | Q | U | 0 1 1 1 0 | size | 1 | Rm | opcode | 0 0 | Rn | Rd |
|
||||
|
@ -9663,7 +9664,7 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.16 AdvSIMD three same
|
||||
/* AdvSIMD three same
|
||||
* 31 30 29 28 24 23 22 21 20 16 15 11 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+------+--------+---+------+------+
|
||||
* | 0 | Q | U | 0 1 1 1 0 | size | 1 | Rm | opcode | 1 | Rn | Rd |
|
||||
|
@ -9932,7 +9933,7 @@ static void handle_shll(DisasContext *s, bool is_q, int size, int rn, int rd)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.17 AdvSIMD two reg misc
|
||||
/* AdvSIMD two reg misc
|
||||
* 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+-----------+--------+-----+------+------+
|
||||
* | 0 | Q | U | 0 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd |
|
||||
|
@ -10444,12 +10445,12 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.13 AdvSIMD scalar x indexed element
|
||||
/* AdvSIMD scalar x indexed element
|
||||
* 31 30 29 28 24 23 22 21 20 19 16 15 12 11 10 9 5 4 0
|
||||
* +-----+---+-----------+------+---+---+------+-----+---+---+------+------+
|
||||
* | 0 1 | U | 1 1 1 1 1 | size | L | M | Rm | opc | H | 0 | Rn | Rd |
|
||||
* +-----+---+-----------+------+---+---+------+-----+---+---+------+------+
|
||||
* C3.6.18 AdvSIMD vector x indexed element
|
||||
* AdvSIMD vector x indexed element
|
||||
* 31 30 29 28 24 23 22 21 20 19 16 15 12 11 10 9 5 4 0
|
||||
* +---+---+---+-----------+------+---+---+------+-----+---+---+------+------+
|
||||
* | 0 | Q | U | 0 1 1 1 1 | size | L | M | Rm | opc | H | 0 | Rn | Rd |
|
||||
|
@ -10899,7 +10900,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* C3.6.19 Crypto AES
|
||||
/* Crypto AES
|
||||
* 31 24 23 22 21 17 16 12 11 10 9 5 4 0
|
||||
* +-----------------+------+-----------+--------+-----+------+------+
|
||||
* | 0 1 0 0 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 | Rn | Rd |
|
||||
|
@ -10962,7 +10963,7 @@ static void disas_crypto_aes(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i32(tcg_decrypt);
|
||||
}
|
||||
|
||||
/* C3.6.20 Crypto three-reg SHA
|
||||
/* Crypto three-reg SHA
|
||||
* 31 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0
|
||||
* +-----------------+------+---+------+---+--------+-----+------+------+
|
||||
* | 0 1 0 1 1 1 1 0 | size | 0 | Rm | 0 | opcode | 0 0 | Rn | Rd |
|
||||
|
@ -11034,7 +11035,7 @@ static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
|
|||
tcg_temp_free_i32(tcg_rm_regno);
|
||||
}
|
||||
|
||||
/* C3.6.21 Crypto two-reg SHA
|
||||
/* Crypto two-reg SHA
|
||||
* 31 24 23 22 21 17 16 12 11 10 9 5 4 0
|
||||
* +-----------------+------+-----------+--------+-----+------+------+
|
||||
* | 0 1 0 1 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 | Rn | Rd |
|
||||
|
|
Loading…
Reference in New Issue