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:
Peter Maydell 2017-09-21 17:42:27 +01:00
commit 0a8066f0c0
28 changed files with 2737 additions and 369 deletions

View File

@ -129,3 +129,4 @@ CONFIG_ACPI=y
CONFIG_SMBIOS=y
CONFIG_ASPEED_SOC=y
CONFIG_GPIO_KEY=y
CONFIG_MSF2=y

View File

@ -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

238
hw/arm/msf2-soc.c Normal file
View File

@ -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)

105
hw/arm/msf2-som.c Normal file
View File

@ -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)

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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

View File

@ -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"

View File

@ -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

160
hw/misc/msf2-sysreg.c Normal file
View File

@ -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)

View File

@ -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"

View File

@ -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

404
hw/ssi/mss-spi.c Normal file
View File

@ -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)

View File

@ -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

289
hw/timer/mss-timer.c Normal file
View File

@ -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)

View File

@ -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,
};

View File

@ -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,
};

67
include/hw/arm/msf2-soc.h Normal file
View File

@ -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

View File

@ -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;

View File

@ -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 */

58
include/hw/ssi/mss-spi.h Normal file
View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 |