/*
 * QEMU model of the Xilinx System Monitor Satellite
 *
 * Copyright (c) 2021 Xilinx Inc.
 *
 * Autogenerated by xregqemu.py 2021-04-27.
 *
 * 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/sysbus.h"
#include "hw/register.h"
#include "qemu/bitops.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"

#include "xlnx-versal-ams.h"

#define TYPE_XLNX_AMS_SAT "xlnx,ams-sat"

#ifndef XLNX_AMS_SAT_ERR_DEBUG
#define XLNX_AMS_SAT_ERR_DEBUG 0
#endif

#define XLNX_AMS_SAT(obj) \
     OBJECT_CHECK(AMS_SAT, (obj), TYPE_XLNX_AMS_SAT)

REG32(REG_PCSR_MASK, 0x0)
    FIELD(REG_PCSR_MASK, SPARE, 27, 5)
    FIELD(REG_PCSR_MASK, STOP_ADC, 26, 1)
    FIELD(REG_PCSR_MASK, DEEP_SLEEP, 25, 1)
    FIELD(REG_PCSR_MASK, SSC_BYPASS, 24, 1)
    FIELD(REG_PCSR_MASK, PCSR_RESERVED, 21, 3)
    FIELD(REG_PCSR_MASK, TEST_SAFE, 20, 1)
    FIELD(REG_PCSR_MASK, SLVERREN, 19, 1)
    FIELD(REG_PCSR_MASK, MEM_CLEAR_TRIGGER, 18, 1)
    FIELD(REG_PCSR_MASK, SYS_RST_MASK, 15, 3)
    FIELD(REG_PCSR_MASK, PWRDN, 14, 1)
    FIELD(REG_PCSR_MASK, DISNPICLK, 13, 1)
    FIELD(REG_PCSR_MASK, APBEN, 12, 1)
    FIELD(REG_PCSR_MASK, SCAN_CLEAR_TRIGGER, 11, 1)
    FIELD(REG_PCSR_MASK, STARTCAL, 10, 1)
    FIELD(REG_PCSR_MASK, FABRICEN, 9, 1)
    FIELD(REG_PCSR_MASK, TRISTATE, 8, 1)
    FIELD(REG_PCSR_MASK, HOLDSTATE, 7, 1)
    FIELD(REG_PCSR_MASK, INITSTATE, 6, 1)
    FIELD(REG_PCSR_MASK, ODISABLE, 2, 4)
    FIELD(REG_PCSR_MASK, GATEREG, 1, 1)
    FIELD(REG_PCSR_MASK, PCOMPLETE, 0, 1)
REG32(REG_PCSR_CONTROL, 0x4)
    FIELD(REG_PCSR_CONTROL, SPARE, 27, 5)
    FIELD(REG_PCSR_CONTROL, STOP_ADC, 26, 1)
    FIELD(REG_PCSR_CONTROL, DEEP_SLEEP, 25, 1)
    FIELD(REG_PCSR_CONTROL, SSC_BYPASS, 24, 1)
    FIELD(REG_PCSR_CONTROL, PCSR_RESERVED, 21, 3)
    FIELD(REG_PCSR_CONTROL, TEST_SAFE, 20, 1)
    FIELD(REG_PCSR_CONTROL, SLVERREN, 19, 1)
    FIELD(REG_PCSR_CONTROL, MEM_CLEAR_TRIGGER, 18, 1)
    FIELD(REG_PCSR_CONTROL, SYS_RST_MASK, 15, 3)
    FIELD(REG_PCSR_CONTROL, PWRDN, 14, 1)
    FIELD(REG_PCSR_CONTROL, DISNPICLK, 13, 1)
    FIELD(REG_PCSR_CONTROL, APBEN, 12, 1)
    FIELD(REG_PCSR_CONTROL, SCAN_CLEAR_TRIGGER, 11, 1)
    FIELD(REG_PCSR_CONTROL, STARTCAL, 10, 1)
    FIELD(REG_PCSR_CONTROL, FABRICEN, 9, 1)
    FIELD(REG_PCSR_CONTROL, TRISTATE, 8, 1)
    FIELD(REG_PCSR_CONTROL, HOLDSTATE, 7, 1)
    FIELD(REG_PCSR_CONTROL, INITSTATE, 6, 1)
    FIELD(REG_PCSR_CONTROL, ODISABLE, 2, 4)
    FIELD(REG_PCSR_CONTROL, GATEREG, 1, 1)
    FIELD(REG_PCSR_CONTROL, PCOMPLETE, 0, 1)
REG32(REG_PCSR_STATUS, 0x8)
    FIELD(REG_PCSR_STATUS, HARD_FAIL_OR, 11, 3)
    FIELD(REG_PCSR_STATUS, HARD_FAIL_AND, 8, 3)
    FIELD(REG_PCSR_STATUS, MEM_CLEAR_PASS, 7, 1)
    FIELD(REG_PCSR_STATUS, MEM_CLEAR_DONE, 6, 1)
    FIELD(REG_PCSR_STATUS, CALERROR, 5, 1)
    FIELD(REG_PCSR_STATUS, CALDONE, 4, 1)
    FIELD(REG_PCSR_STATUS, INCAL, 3, 1)
    FIELD(REG_PCSR_STATUS, SCAN_CLEAR_PASS, 2, 1)
    FIELD(REG_PCSR_STATUS, SCAN_CLEAR_DONE, 1, 1)
    FIELD(REG_PCSR_STATUS, PCSRLOCK, 0, 1)
REG32(REG_PCSR_LOCK, 0xc)
    FIELD(REG_PCSR_LOCK, STATE, 0, 1)
REG32(REG_ITR, 0x40)
    FIELD(REG_ITR, DEEP_SLEEP_RDY, 6, 1)
    FIELD(REG_ITR, FBC_OUT_ERROR, 5, 1)
    FIELD(REG_ITR, REFIF_VIN_DROOP, 4, 1)
    FIELD(REG_ITR, VREF_ERROR, 3, 1)
    FIELD(REG_ITR, SSC_ERROR, 2, 1)
    FIELD(REG_ITR, CAL_DEASSERT, 1, 1)
    FIELD(REG_ITR, CAL_ASSERT, 0, 1)
REG32(REG_ISR, 0x44)
    FIELD(REG_ISR, DEEP_SLEEP_RDY, 6, 1)
    FIELD(REG_ISR, FBC_OUT_ERROR, 5, 1)
    FIELD(REG_ISR, REFIF_VIN_DROOP, 4, 1)
    FIELD(REG_ISR, VREF_ERROR, 3, 1)
    FIELD(REG_ISR, SSC_ERROR, 2, 1)
    FIELD(REG_ISR, CAL_DEASSERT, 1, 1)
    FIELD(REG_ISR, CAL_ASSERT, 0, 1)
REG32(REG_IMR0, 0x48)
    FIELD(REG_IMR0, DEEP_SLEEP_RDY, 6, 1)
    FIELD(REG_IMR0, FBC_OUT_ERROR, 5, 1)
    FIELD(REG_IMR0, REFIF_VIN_DROOP, 4, 1)
    FIELD(REG_IMR0, VREF_ERROR, 3, 1)
    FIELD(REG_IMR0, SSC_ERROR, 2, 1)
    FIELD(REG_IMR0, CAL_DEASSERT, 1, 1)
    FIELD(REG_IMR0, CAL_ASSERT, 0, 1)
REG32(REG_IER0, 0x4c)
    FIELD(REG_IER0, DEEP_SLEEP_RDY, 6, 1)
    FIELD(REG_IER0, FBC_OUT_ERROR, 5, 1)
    FIELD(REG_IER0, REFIF_VIN_DROOP, 4, 1)
    FIELD(REG_IER0, VREF_ERROR, 3, 1)
    FIELD(REG_IER0, SSC_ERROR, 2, 1)
    FIELD(REG_IER0, CAL_DEASSERT, 1, 1)
    FIELD(REG_IER0, CAL_ASSERT, 0, 1)
REG32(REG_IDR0, 0x50)
    FIELD(REG_IDR0, DEEP_SLEEP_RDY, 6, 1)
    FIELD(REG_IDR0, FBC_OUT_ERROR, 5, 1)
    FIELD(REG_IDR0, REFIF_VIN_DROOP, 4, 1)
    FIELD(REG_IDR0, VREF_ERROR, 3, 1)
    FIELD(REG_IDR0, SSC_ERROR, 2, 1)
    FIELD(REG_IDR0, CAL_DEASSERT, 1, 1)
    FIELD(REG_IDR0, CAL_ASSERT, 0, 1)
REG32(REG_IMR1, 0x54)
    FIELD(REG_IMR1, DEEP_SLEEP_RDY, 6, 1)
    FIELD(REG_IMR1, FBC_OUT_ERROR, 5, 1)
    FIELD(REG_IMR1, REFIF_VIN_DROOP, 4, 1)
    FIELD(REG_IMR1, VREF_ERROR, 3, 1)
    FIELD(REG_IMR1, SSC_ERROR, 2, 1)
    FIELD(REG_IMR1, CAL_DEASSERT, 1, 1)
    FIELD(REG_IMR1, CAL_ASSERT, 0, 1)
REG32(REG_IER1, 0x58)
    FIELD(REG_IER1, DEEP_SLEEP_RDY, 6, 1)
    FIELD(REG_IER1, FBC_OUT_ERROR, 5, 1)
    FIELD(REG_IER1, REFIF_VIN_DROOP, 4, 1)
    FIELD(REG_IER1, VREF_ERROR, 3, 1)
    FIELD(REG_IER1, SSC_ERROR, 2, 1)
    FIELD(REG_IER1, CAL_DEASSERT, 1, 1)
    FIELD(REG_IER1, CAL_ASSERT, 0, 1)
REG32(REG_IDR1, 0x5c)
    FIELD(REG_IDR1, DEEP_SLEEP_RDY, 6, 1)
    FIELD(REG_IDR1, FBC_OUT_ERROR, 5, 1)
    FIELD(REG_IDR1, REFIF_VIN_DROOP, 4, 1)
    FIELD(REG_IDR1, VREF_ERROR, 3, 1)
    FIELD(REG_IDR1, SSC_ERROR, 2, 1)
    FIELD(REG_IDR1, CAL_DEASSERT, 1, 1)
    FIELD(REG_IDR1, CAL_ASSERT, 0, 1)
REG32(REG_IOR, 0x60)
    FIELD(REG_IOR, OFFSET, 0, 5)
REG32(TOKEN_MNGR, 0x100)
    FIELD(TOKEN_MNGR, TOKEN_RELEASE_COUNT, 11, 6)
    FIELD(TOKEN_MNGR, TOKEN_RELEASE_SELECT, 10, 1)
    FIELD(TOKEN_MNGR, FORCE_ADC_START, 9, 1)
    FIELD(TOKEN_MNGR, DISABLE_TOKEN_ADC_CTRL, 8, 1)
    FIELD(TOKEN_MNGR, VREF_TOKEN_COUNT, 0, 8)
REG32(ADC_CTRL0, 0x104)
    FIELD(ADC_CTRL0, TRACK_GOQ_CC, 16, 8)
    FIELD(ADC_CTRL0, TRACK_TEMP_CC, 8, 8)
    FIELD(ADC_CTRL0, TRACK_VMEAS_CC, 0, 8)
REG32(ADC_CTRL1, 0x108)
    FIELD(ADC_CTRL1, ANA_START_DLY_CONFIG, 6, 3)
    FIELD(ADC_CTRL1, TEMP_RESET_CC, 3, 3)
    FIELD(ADC_CTRL1, VMEAS_RESET_CC, 0, 3)
REG32(ADC_CTRL2, 0x10c)
    FIELD(ADC_CTRL2, DISABLE_REF_VIN_DROOP, 14, 1)
    FIELD(ADC_CTRL2, REF_SAMP_TIME, 8, 6)
    FIELD(ADC_CTRL2, REF_SAMP_START_TIME, 0, 8)
REG32(SLEEP_WAKE_UP, 0x110)
    FIELD(SLEEP_WAKE_UP, SLEEP_WAKEUP, 0, 3)
REG32(SEQ_CONFIG, 0x114)
    FIELD(SEQ_CONFIG, EVENT_MODE_EN, 5, 1)
    FIELD(SEQ_CONFIG, WAIT_FOR_CAL_N, 4, 1)
    FIELD(SEQ_CONFIG, DISABLE_SYSTEM_SEQUENCE, 3, 1)
    FIELD(SEQ_CONFIG, NO_SYNC, 2, 1)
    FIELD(SEQ_CONFIG, REF_SAMPLE_CONST, 1, 1)
    FIELD(SEQ_CONFIG, REF_SAMPLE, 0, 1)
REG32(SYS_SEQ_CONFIG, 0x118)
    FIELD(SYS_SEQ_CONFIG, PSSR, 6, 1)
    FIELD(SYS_SEQ_CONFIG, BIP, 5, 1)
    FIELD(SYS_SEQ_CONFIG, UNI, 4, 1)
    FIELD(SYS_SEQ_CONFIG, VCCINT, 3, 1)
    FIELD(SYS_SEQ_CONFIG, TSENS, 2, 1)
    FIELD(SYS_SEQ_CONFIG, VREF_OFFSET, 1, 1)
    FIELD(SYS_SEQ_CONFIG, VREF, 0, 1)
REG32(VCCINT_MEAS_CONFIG, 0x11c)
    FIELD(VCCINT_MEAS_CONFIG, ADDR_ID, 6, 7)
    FIELD(VCCINT_MEAS_CONFIG, MODE, 4, 2)
    FIELD(VCCINT_MEAS_CONFIG, AMUX_CTRL, 0, 4)
REG32(TSENS_MEAS_CONFIG, 0x120)
    FIELD(TSENS_MEAS_CONFIG, ADDR_ID, 2, 7)
    FIELD(TSENS_MEAS_CONFIG, SEL_TSENS_OUT, 0, 2)
REG32(VCAL_MEAS_CONFIG, 0x124)
    FIELD(VCAL_MEAS_CONFIG, BIP_ACTUAL, 28, 4)
    FIELD(VCAL_MEAS_CONFIG, UNI_ACTUAL, 24, 4)
    FIELD(VCAL_MEAS_CONFIG, SM_BIP_TARGET, 20, 4)
    FIELD(VCAL_MEAS_CONFIG, SM_UNI_TARGET, 16, 4)
    FIELD(VCAL_MEAS_CONFIG, BIP_OFFSET, 12, 4)
    FIELD(VCAL_MEAS_CONFIG, UNI_LOW_CM_OFFSET, 8, 4)
    FIELD(VCAL_MEAS_CONFIG, SM_HI_CM_OFFSET, 4, 4)
    FIELD(VCAL_MEAS_CONFIG, SM_LOW_CM_OFFSET, 0, 4)
REG32(TSENS_CAL_MEAS_CONFIG, 0x128)
    FIELD(TSENS_CAL_MEAS_CONFIG, MOD_ACTUAL, 8, 2)
    FIELD(TSENS_CAL_MEAS_CONFIG, MOD_OFFSET, 6, 2)
    FIELD(TSENS_CAL_MEAS_CONFIG, TSENS_OFFSET, 4, 2)
    FIELD(TSENS_CAL_MEAS_CONFIG, SM_TSENS_TARGET, 0, 4)
REG32(VREF_MODE_UNI, 0x12c)
    FIELD(VREF_MODE_UNI, SEL_UNI, 0, 1)
REG32(CAL_AVG_SEL, 0x130)
    FIELD(CAL_AVG_SEL, BIP_GE, 6, 3)
    FIELD(CAL_AVG_SEL, UNI_GE, 3, 3)
    FIELD(CAL_AVG_SEL, TSENS_GE, 0, 3)
REG32(CAL_MODE_TF, 0x134)
    FIELD(CAL_MODE_TF, SM_EXT, 13, 8)
    FIELD(CAL_MODE_TF, TSENS, 9, 4)
    FIELD(CAL_MODE_TF, BIP, 6, 3)
    FIELD(CAL_MODE_TF, UNI, 3, 3)
    FIELD(CAL_MODE_TF, SM, 0, 3)
REG32(CAL_MOD_TF, 0x138)
    FIELD(CAL_MOD_TF, REF_MOD_GAIN, 0, 7)
REG32(CAL_TSENS_TF, 0x13c)
    FIELD(CAL_TSENS_TF, TSENSE_CONV_OFFSET, 12, 16)
    FIELD(CAL_TSENS_TF, TSENSE_CONV_GAIN, 0, 12)
REG32(CAL_SM_REF_TARGET, 0x140)
    FIELD(CAL_SM_REF_TARGET, VAL, 0, 21)
REG32(CAL_SM_BIP_TSENS, 0x144)
    FIELD(CAL_SM_BIP_TSENS, TSENS_GE_SEL, 1, 1)
    FIELD(CAL_SM_BIP_TSENS, BIP_GE_SEL, 0, 1)
REG32(DISABLE_CAL_CLEAR_ON_VREF_ERROR, 0x148)
    FIELD(DISABLE_CAL_CLEAR_ON_VREF_ERROR, DISABLE_CAL_CLEAR, 0, 1)
REG32(CAL_DATA_BYPASS, 0x14c)
    FIELD(CAL_DATA_BYPASS, DISABLE_VCCINT, 2, 1)
    FIELD(CAL_DATA_BYPASS, DISABLE_TSENS, 1, 1)
    FIELD(CAL_DATA_BYPASS, DISABLE_USER_VMEAS, 0, 1)
REG32(CAL_OFFSET_DISABLE, 0x150)
    FIELD(CAL_OFFSET_DISABLE, BIP, 3, 1)
    FIELD(CAL_OFFSET_DISABLE, UNI, 2, 1)
    FIELD(CAL_OFFSET_DISABLE, TSENS, 1, 1)
    FIELD(CAL_OFFSET_DISABLE, SM, 0, 1)
REG32(CAL_GAIN_DISABLE, 0x154)
    FIELD(CAL_GAIN_DISABLE, BIP, 3, 1)
    FIELD(CAL_GAIN_DISABLE, UNI, 2, 1)
    FIELD(CAL_GAIN_DISABLE, TSENS, 1, 1)
    FIELD(CAL_GAIN_DISABLE, SM, 0, 1)
REG32(CAL_OVERRIDE, 0x158)
    FIELD(CAL_OVERRIDE, OVERRIDE, 24, 1)
    FIELD(CAL_OVERRIDE, ENABLE, 23, 1)
    FIELD(CAL_OVERRIDE, ADDR, 18, 5)
    FIELD(CAL_OVERRIDE, DATA, 0, 18)
REG32(GOQ_TEST, 0x15c)
    FIELD(GOQ_TEST, GOQ_FABRIC_PASS_EN, 2, 1)
    FIELD(GOQ_TEST, GOQ_FABRIC_MODE, 1, 1)
    FIELD(GOQ_TEST, GOQ_EN, 0, 1)
REG32(DISABLE_REFIF_V2I_BIAS, 0x160)
    FIELD(DISABLE_REFIF_V2I_BIAS, VAL, 0, 1)
REG32(ANA_SPARE_MUX0, 0x164)
    FIELD(ANA_SPARE_MUX0, VAL, 0, 2)
REG32(ANA_SPARE_MUX1, 0x168)
    FIELD(ANA_SPARE_MUX1, VAL, 0, 3)
REG32(FABRIC_IF_CTRL, 0x16c)
    FIELD(FABRIC_IF_CTRL, FBC_IN_OR_SEL, 7, 2)
    FIELD(FABRIC_IF_CTRL, FBC_OUT_EN, 3, 4)
    FIELD(FABRIC_IF_CTRL, FABRIC_DEBUG_SEL, 0, 3)
REG32(DIGITAL_BYPASS, 0x170)
    FIELD(DIGITAL_BYPASS, ADC_BYPASS_MODE, 19, 2)
    FIELD(DIGITAL_BYPASS, DATA, 0, 19)
REG32(DEM_CTRL, 0x174)
    FIELD(DEM_CTRL, CAP_USER_VALUE, 7, 2)
    FIELD(DEM_CTRL, DISABLE_CAP, 6, 1)
    FIELD(DEM_CTRL, BIP_USER_VALUE, 5, 1)
    FIELD(DEM_CTRL, DISABLE_BIP, 4, 1)
    FIELD(DEM_CTRL, CURR_USER_VALUE, 1, 3)
    FIELD(DEM_CTRL, DISABLE_CURR, 0, 1)
REG32(DFX, 0x178)
    FIELD(DFX, NPI_CSSD_TRIG_N, 0, 2)
REG32(TSENS_BIAS_CTRL, 0x17c)
    FIELD(TSENS_BIAS_CTRL, VAL, 0, 2)
REG32(EFUSE_CONFIG0, 0x180)
    FIELD(EFUSE_CONFIG0, PROCESS, 16, 16)
    FIELD(EFUSE_CONFIG0, DELTA, 12, 4)
    FIELD(EFUSE_CONFIG0, SLOPE, 6, 6)
    FIELD(EFUSE_CONFIG0, OFFSET, 0, 6)
REG32(EFUSE_CONFIG1, 0x184)
    FIELD(EFUSE_CONFIG1, DIG_SPARE, 19, 13)
    FIELD(EFUSE_CONFIG1, ANA_SPARE, 17, 2)
    FIELD(EFUSE_CONFIG1, EXT_OFFSET, 11, 6)
    FIELD(EFUSE_CONFIG1, BJT_OFFSET, 7, 4)
    FIELD(EFUSE_CONFIG1, RESISTOR, 0, 7)
REG32(TSENS_DELTA, 0x188)
    FIELD(TSENS_DELTA, EXT_OFFSET_SEL, 1, 1)
    FIELD(TSENS_DELTA, SEL, 0, 1)
REG32(ABIST_START, 0x18c)
    FIELD(ABIST_START, VAL, 0, 1)
REG32(ABIST_TEST, 0x190)
    FIELD(ABIST_TEST, ABIST_MODE, 10, 1)
    FIELD(ABIST_TEST, ABIST_CHAIN_LEN, 2, 8)
    FIELD(ABIST_TEST, ANALOG_MUX, 0, 2)
REG32(PSRR_CLK_CTRL, 0x194)
    FIELD(PSRR_CLK_CTRL, DISABLE_TEMP_PSRR_CLK_MOD, 1, 1)
    FIELD(PSRR_CLK_CTRL, DISABLE_VMEAS_PSRR_CLK_MOD, 0, 1)
REG32(CDC_SEL, 0x198)
    FIELD(CDC_SEL, ROOT_SEL, 0, 1)
REG32(TEST_SPARE0, 0x19c)
    FIELD(TEST_SPARE0, VAL, 0, 13)
REG32(TEST_SPARE1, 0x1a0)
    FIELD(TEST_SPARE1, VAL, 0, 13)
REG32(CONFIG_CONTROL, 0x500)
    FIELD(CONFIG_CONTROL, CONFIG_UPDATE, 0, 1)
REG32(USER_SEQ0, 0x504)
    FIELD(USER_SEQ0, SEQ_CH3, 24, 8)
    FIELD(USER_SEQ0, SEQ_CH2, 16, 8)
    FIELD(USER_SEQ0, SEQ_CH1, 8, 8)
    FIELD(USER_SEQ0, SEQ_CH0, 0, 8)
REG32(USER_SEQ1, 0x508)
    FIELD(USER_SEQ1, SEQ_CH7, 24, 8)
    FIELD(USER_SEQ1, SEQ_CH6, 16, 8)
    FIELD(USER_SEQ1, SEQ_CH5, 8, 8)
    FIELD(USER_SEQ1, SEQ_CH4, 0, 8)
REG32(USER_SEQ2, 0x50c)
    FIELD(USER_SEQ2, SEQ_CH11, 24, 8)
    FIELD(USER_SEQ2, SEQ_CH10, 16, 8)
    FIELD(USER_SEQ2, SEQ_CH9, 8, 8)
    FIELD(USER_SEQ2, SEQ_CH8, 0, 8)
REG32(USER_SEQ3, 0x510)
    FIELD(USER_SEQ3, SEQ_CH15, 24, 8)
    FIELD(USER_SEQ3, SEQ_CH14, 16, 8)
    FIELD(USER_SEQ3, SEQ_CH13, 8, 8)
    FIELD(USER_SEQ3, SEQ_CH12, 0, 8)
REG32(USER_SEQ4, 0x514)
    FIELD(USER_SEQ4, SEQ_CH19, 24, 8)
    FIELD(USER_SEQ4, SEQ_CH18, 16, 8)
    FIELD(USER_SEQ4, SEQ_CH17, 8, 8)
    FIELD(USER_SEQ4, SEQ_CH16, 0, 8)
REG32(USER_SEQ5, 0x518)
    FIELD(USER_SEQ5, SEQ_CH23, 24, 8)
    FIELD(USER_SEQ5, SEQ_CH22, 16, 8)
    FIELD(USER_SEQ5, SEQ_CH21, 8, 8)
    FIELD(USER_SEQ5, SEQ_CH20, 0, 8)
REG32(USER_SEQ6, 0x51c)
    FIELD(USER_SEQ6, SEQ_CH27, 24, 8)
    FIELD(USER_SEQ6, SEQ_CH26, 16, 8)
    FIELD(USER_SEQ6, SEQ_CH25, 8, 8)
    FIELD(USER_SEQ6, SEQ_CH24, 0, 8)
REG32(USER_SEQ7, 0x520)
    FIELD(USER_SEQ7, SEQ_CH31, 24, 8)
    FIELD(USER_SEQ7, SEQ_CH30, 16, 8)
    FIELD(USER_SEQ7, SEQ_CH29, 8, 8)
    FIELD(USER_SEQ7, SEQ_CH28, 0, 8)
    SHARED_FIELD(USER_SEQ_CH_NEXT, 8, 8)
    SHARED_FIELD(USER_SEQ_CH_SLEEP_MODE, 7, 1)
    SHARED_FIELD(USER_SEQ_CH_END_OF_SEQ, 6, 1)
    SHARED_FIELD(USER_SEQ_CH_MEAS_ID, 0, 6)
REG32(MEASURE0_CONFIG, 0x524)
    FIELD(MEASURE0_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE0_CONFIG, MODE, 20, 2)
    FIELD(MEASURE0_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE0_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE0_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE1_CONFIG, 0x528)
    FIELD(MEASURE1_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE1_CONFIG, MODE, 20, 2)
    FIELD(MEASURE1_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE1_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE1_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE2_CONFIG, 0x52c)
    FIELD(MEASURE2_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE2_CONFIG, MODE, 20, 2)
    FIELD(MEASURE2_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE2_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE2_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE3_CONFIG, 0x530)
    FIELD(MEASURE3_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE3_CONFIG, MODE, 20, 2)
    FIELD(MEASURE3_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE3_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE3_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE4_CONFIG, 0x534)
    FIELD(MEASURE4_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE4_CONFIG, MODE, 20, 2)
    FIELD(MEASURE4_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE4_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE4_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE5_CONFIG, 0x538)
    FIELD(MEASURE5_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE5_CONFIG, MODE, 20, 2)
    FIELD(MEASURE5_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE5_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE5_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE6_CONFIG, 0x53c)
    FIELD(MEASURE6_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE6_CONFIG, MODE, 20, 2)
    FIELD(MEASURE6_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE6_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE6_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE7_CONFIG, 0x540)
    FIELD(MEASURE7_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE7_CONFIG, MODE, 20, 2)
    FIELD(MEASURE7_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE7_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE7_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE8_CONFIG, 0x544)
    FIELD(MEASURE8_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE8_CONFIG, MODE, 20, 2)
    FIELD(MEASURE8_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE8_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE8_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE9_CONFIG, 0x548)
    FIELD(MEASURE9_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE9_CONFIG, MODE, 20, 2)
    FIELD(MEASURE9_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE9_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE9_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE10_CONFIG, 0x54c)
    FIELD(MEASURE10_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE10_CONFIG, MODE, 20, 2)
    FIELD(MEASURE10_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE10_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE10_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE11_CONFIG, 0x550)
    FIELD(MEASURE11_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE11_CONFIG, MODE, 20, 2)
    FIELD(MEASURE11_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE11_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE11_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE12_CONFIG, 0x554)
    FIELD(MEASURE12_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE12_CONFIG, MODE, 20, 2)
    FIELD(MEASURE12_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE12_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE12_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE13_CONFIG, 0x558)
    FIELD(MEASURE13_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE13_CONFIG, MODE, 20, 2)
    FIELD(MEASURE13_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE13_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE13_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE14_CONFIG, 0x55c)
    FIELD(MEASURE14_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE14_CONFIG, MODE, 20, 2)
    FIELD(MEASURE14_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE14_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE14_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE15_CONFIG, 0x560)
    FIELD(MEASURE15_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE15_CONFIG, MODE, 20, 2)
    FIELD(MEASURE15_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE15_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE15_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE16_CONFIG, 0x564)
    FIELD(MEASURE16_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE16_CONFIG, MODE, 20, 2)
    FIELD(MEASURE16_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE16_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE16_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE17_CONFIG, 0x568)
    FIELD(MEASURE17_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE17_CONFIG, MODE, 20, 2)
    FIELD(MEASURE17_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE17_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE17_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE18_CONFIG, 0x56c)
    FIELD(MEASURE18_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE18_CONFIG, MODE, 20, 2)
    FIELD(MEASURE18_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE18_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE18_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE19_CONFIG, 0x570)
    FIELD(MEASURE19_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE19_CONFIG, MODE, 20, 2)
    FIELD(MEASURE19_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE19_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE19_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE20_CONFIG, 0x574)
    FIELD(MEASURE20_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE20_CONFIG, MODE, 20, 2)
    FIELD(MEASURE20_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE20_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE20_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE21_CONFIG, 0x578)
    FIELD(MEASURE21_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE21_CONFIG, MODE, 20, 2)
    FIELD(MEASURE21_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE21_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE21_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE22_CONFIG, 0x57c)
    FIELD(MEASURE22_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE22_CONFIG, MODE, 20, 2)
    FIELD(MEASURE22_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE22_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE22_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE23_CONFIG, 0x580)
    FIELD(MEASURE23_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE23_CONFIG, MODE, 20, 2)
    FIELD(MEASURE23_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE23_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE23_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE24_CONFIG, 0x584)
    FIELD(MEASURE24_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE24_CONFIG, MODE, 20, 2)
    FIELD(MEASURE24_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE24_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE24_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE25_CONFIG, 0x588)
    FIELD(MEASURE25_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE25_CONFIG, MODE, 20, 2)
    FIELD(MEASURE25_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE25_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE25_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE26_CONFIG, 0x58c)
    FIELD(MEASURE26_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE26_CONFIG, MODE, 20, 2)
    FIELD(MEASURE26_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE26_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE26_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE27_CONFIG, 0x590)
    FIELD(MEASURE27_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE27_CONFIG, MODE, 20, 2)
    FIELD(MEASURE27_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE27_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE27_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE28_CONFIG, 0x594)
    FIELD(MEASURE28_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE28_CONFIG, MODE, 20, 2)
    FIELD(MEASURE28_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE28_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE28_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE29_CONFIG, 0x598)
    FIELD(MEASURE29_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE29_CONFIG, MODE, 20, 2)
    FIELD(MEASURE29_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE29_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE29_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE30_CONFIG, 0x59c)
    FIELD(MEASURE30_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE30_CONFIG, MODE, 20, 2)
    FIELD(MEASURE30_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE30_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE30_CONFIG, ABUS_SW0, 0, 8)
REG32(MEASURE31_CONFIG, 0x5a0)
    FIELD(MEASURE31_CONFIG, ADDR_ID, 22, 8)
    FIELD(MEASURE31_CONFIG, MODE, 20, 2)
    FIELD(MEASURE31_CONFIG, AMUX_CTRL, 16, 4)
    FIELD(MEASURE31_CONFIG, ABUS_SW1, 8, 8)
    FIELD(MEASURE31_CONFIG, ABUS_SW0, 0, 8)
REG32(EXT_MUX_ADDR0, 0x5a4)
    FIELD(EXT_MUX_ADDR0, EXT_MUX_CH7, 28, 4)
    FIELD(EXT_MUX_ADDR0, EXT_MUX_CH6, 24, 4)
    FIELD(EXT_MUX_ADDR0, EXT_MUX_CH5, 20, 4)
    FIELD(EXT_MUX_ADDR0, EXT_MUX_CH4, 16, 4)
    FIELD(EXT_MUX_ADDR0, EXT_MUX_CH3, 12, 4)
    FIELD(EXT_MUX_ADDR0, EXT_MUX_CH2, 8, 4)
    FIELD(EXT_MUX_ADDR0, EXT_MUX_CH1, 4, 4)
    FIELD(EXT_MUX_ADDR0, EXT_MUX_CH0, 0, 4)
REG32(EXT_MUX_ADDR1, 0x5a8)
    FIELD(EXT_MUX_ADDR1, EXT_MUX_CH15, 28, 4)
    FIELD(EXT_MUX_ADDR1, EXT_MUX_CH14, 24, 4)
    FIELD(EXT_MUX_ADDR1, EXT_MUX_CH13, 20, 4)
    FIELD(EXT_MUX_ADDR1, EXT_MUX_CH12, 16, 4)
    FIELD(EXT_MUX_ADDR1, EXT_MUX_CH11, 12, 4)
    FIELD(EXT_MUX_ADDR1, EXT_MUX_CH10, 8, 4)
    FIELD(EXT_MUX_ADDR1, EXT_MUX_CH9, 4, 4)
    FIELD(EXT_MUX_ADDR1, EXT_MUX_CH8, 0, 4)
REG32(EXT_MUX_EN, 0x5ac)
    FIELD(EXT_MUX_EN, EXT_MUX_EN, 0, 16)
REG32(CONFIG_UPDATE_STATUS, 0x5b0)
    FIELD(CONFIG_UPDATE_STATUS, CONFIGURED, 0, 1)
REG32(CAL_STATUS, 0x5b4)
    FIELD(CAL_STATUS, CALLIBRATED, 2, 1)
    FIELD(CAL_STATUS, LOCAL_REFERENCE_CALIBRATED, 1, 1)
    FIELD(CAL_STATUS, LOCAL_REFERENCE_UP, 0, 1)
REG32(CAL_STATUS_DEBUG, 0x5b8)
    FIELD(CAL_STATUS_DEBUG, TOKEN_LATE, 6, 1)
    FIELD(CAL_STATUS_DEBUG, TOKEN_EARLY, 5, 1)
    FIELD(CAL_STATUS_DEBUG, TOKEN_SYNC, 4, 1)
    FIELD(CAL_STATUS_DEBUG, BIP_GE, 3, 1)
    FIELD(CAL_STATUS_DEBUG, UNI_GE, 2, 1)
    FIELD(CAL_STATUS_DEBUG, TSENS_GE, 1, 1)
    FIELD(CAL_STATUS_DEBUG, SM_GE, 0, 1)
REG32(SM_GE, 0x5bc)
    FIELD(SM_GE, VAL, 0, 11)
REG32(TSENS_GE, 0x5c0)
    FIELD(TSENS_GE, VAL, 0, 11)
REG32(UNI_GE, 0x5c4)
    FIELD(UNI_GE, VAL, 0, 11)
REG32(BIP_GE, 0x5c8)
    FIELD(BIP_GE, VAL, 0, 11)
REG32(SM_LOW_CM_OFFSET, 0x5cc)
    FIELD(SM_LOW_CM_OFFSET, VAL, 0, 18)
REG32(SM_HI_CM_OFFSET, 0x5d0)
    FIELD(SM_HI_CM_OFFSET, VAL, 0, 18)
REG32(MOD_OFFSET, 0x5d4)
    FIELD(MOD_OFFSET, VAL, 0, 18)
REG32(TSENS_OFFSET, 0x5d8)
    FIELD(TSENS_OFFSET, VAL, 0, 18)
REG32(UNI_LOW_CM_OFFSET, 0x5dc)
    FIELD(UNI_LOW_CM_OFFSET, VAL, 0, 18)
REG32(BIP_OFFSET, 0x5e0)
    FIELD(BIP_OFFSET, VAL, 0, 18)
REG32(SM_REF_ACTUAL, 0x5e4)
    FIELD(SM_REF_ACTUAL, VAL, 0, 18)
REG32(MOD_ACTUAL, 0x5e8)
    FIELD(MOD_ACTUAL, VAL, 0, 18)
REG32(UNI_ACTUAL, 0x5ec)
    FIELD(UNI_ACTUAL, VAL, 0, 18)
REG32(BIP_ACTUAL, 0x5f0)
    FIELD(BIP_ACTUAL, VAL, 0, 18)
REG32(SM_TSENS_TARGET, 0x5f4)
    FIELD(SM_TSENS_TARGET, VAL, 0, 18)
REG32(SM_UNI_TARGET, 0x5f8)
    FIELD(SM_UNI_TARGET, VAL, 0, 18)
REG32(SM_BIP_TARGET, 0x5fc)
    FIELD(SM_BIP_TARGET, VAL, 0, 18)
REG32(TSENS_MEAS, 0x600)
    FIELD(TSENS_MEAS, VAL, 0, 18)
REG32(ABIST_STATUS, 0x604)
    FIELD(ABIST_STATUS, ABIST_PASS, 1, 4)
    FIELD(ABIST_STATUS, COMPLETE, 0, 1)
REG32(ANA_SPARE_OUT, 0x608)
    FIELD(ANA_SPARE_OUT, VAL, 0, 2)
REG32(DEEP_SLEEP_STATUS, 0x60c)
    FIELD(DEEP_SLEEP_STATUS, HIBERNATING, 0, 1)

#define XLNX_AMS_SAT_R_MAX (R_DEEP_SLEEP_STATUS + 1)

#define R_REG_PCSR_LOCK_UNLOCK_CODE (0xF9E8D7C6)

#define AMS_SAT_MEAS_VAL_UNDEFINED  FLT_MAX

enum {
    AMS_SAT_VOLT_MEAS_LAST_SLOT = (R_MEASURE31_CONFIG - R_MEASURE0_CONFIG),
    AMS_SAT_VCCINT_MEAS_SLOT,
    AMS_SAT_TSENS_MEAS_SLOT,

    AMS_SAT_SENSOR_TOTAL_SLOTS,
};

/*
 * Helper to indicate completion of built-in operations
 * upon AMS_SAT exit from reset.
 */
#define AMS_SAT_RESET_EXIT_BITSET(s, r, b) do {       \
        (s)->regs[R_ ## r] |= R_ ## r ## _ ## b ## _MASK;  \
    } while (0)

typedef struct AMS_SAT {
    SysBusDevice parent_obj;
    MemoryRegion iomem;
    qemu_irq irq_0;
    qemu_irq irq_1;

    Object *ams_root;
    unsigned instance;
    float meas_vals[AMS_SAT_SENSOR_TOTAL_SLOTS];
    bool reg_reset;

    uint32_t regs[XLNX_AMS_SAT_R_MAX];
    RegisterInfo regs_info[XLNX_AMS_SAT_R_MAX];
} AMS_SAT;

static void reg_isr_update_irq(AMS_SAT *s)
{
    bool pending_0 = !!(s->regs[R_REG_ISR] & ~s->regs[R_REG_IMR0]);
    bool pending_1 = !!(s->regs[R_REG_ISR] & ~s->regs[R_REG_IMR1]);

    qemu_set_irq(s->irq_0, pending_0);
    qemu_set_irq(s->irq_1, pending_1);
}

static void reg_isr_postw(RegisterInfo *reg, uint64_t val64)
{
    AMS_SAT *s = XLNX_AMS_SAT(reg->opaque);
    reg_isr_update_irq(s);
}

static uint64_t reg_itr_prew(RegisterInfo *reg, uint64_t val64)
{
    AMS_SAT *s = XLNX_AMS_SAT(reg->opaque);
    uint32_t val = val64;

    s->regs[R_REG_ISR] |= val;
    reg_isr_update_irq(s);
    return 0;
}

static uint64_t reg_idr0_prew(RegisterInfo *reg, uint64_t val64)
{
    AMS_SAT *s = XLNX_AMS_SAT(reg->opaque);
    uint32_t val = val64;

    s->regs[R_REG_IMR0] |= val;
    reg_isr_update_irq(s);
    return 0;
}

static uint64_t reg_idr1_prew(RegisterInfo *reg, uint64_t val64)
{
    AMS_SAT *s = XLNX_AMS_SAT(reg->opaque);
    uint32_t val = val64;

    s->regs[R_REG_IMR1] |= val;
    reg_isr_update_irq(s);
    return 0;
}

static uint64_t reg_ier1_prew(RegisterInfo *reg, uint64_t val64)
{
    AMS_SAT *s = XLNX_AMS_SAT(reg->opaque);
    uint32_t val = val64;

    s->regs[R_REG_IMR1] &= ~val;
    reg_isr_update_irq(s);
    return 0;
}

static uint64_t reg_ier0_prew(RegisterInfo *reg, uint64_t val64)
{
    AMS_SAT *s = XLNX_AMS_SAT(reg->opaque);
    uint32_t val = val64;

    s->regs[R_REG_IMR0] &= ~val;
    reg_isr_update_irq(s);
    return 0;
}

static void ams_sat_reset_enter(Object *obj, ResetType type)
{
    AMS_SAT *s = XLNX_AMS_SAT(obj);
    unsigned int i;

    s->reg_reset = true;
    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
        register_reset(&s->regs_info[i]);
    }
    s->reg_reset = false;
}

static void ams_sat_reset_hold(Object *obj)
{
    AMS_SAT *s = XLNX_AMS_SAT(obj);

    reg_isr_update_irq(s);
}

static void ams_sat_reset_exit(Object *obj)
{
    AMS_SAT *s = XLNX_AMS_SAT(obj);

    /* Model built-in operations that complete upon reset exit */
    AMS_SAT_RESET_EXIT_BITSET(s, CAL_STATUS, CALLIBRATED);
    AMS_SAT_RESET_EXIT_BITSET(s, CAL_STATUS, LOCAL_REFERENCE_CALIBRATED);
    AMS_SAT_RESET_EXIT_BITSET(s, CAL_STATUS, LOCAL_REFERENCE_UP);

    AMS_SAT_RESET_EXIT_BITSET(s, CAL_STATUS_DEBUG, TOKEN_SYNC);
    AMS_SAT_RESET_EXIT_BITSET(s, CAL_STATUS_DEBUG, BIP_GE);
    AMS_SAT_RESET_EXIT_BITSET(s, CAL_STATUS_DEBUG, UNI_GE);
    AMS_SAT_RESET_EXIT_BITSET(s, CAL_STATUS_DEBUG, TSENS_GE);
    AMS_SAT_RESET_EXIT_BITSET(s, CAL_STATUS_DEBUG, SM_GE);
}

static void ams_sat_reset_pulse(AMS_SAT *s)
{
    Object *obj = OBJECT(s);

    ams_sat_reset_enter(obj, RESET_TYPE_COLD);
    ams_sat_reset_hold(obj);
    ams_sat_reset_exit(obj);
}

static void ams_sat_deep_sleep_update(AMS_SAT *s, bool on)
{
    ARRAY_FIELD_DP32(s->regs, DEEP_SLEEP_STATUS, HIBERNATING, on);
    if (on) {
        ARRAY_FIELD_DP32(s->regs, REG_ISR, DEEP_SLEEP_RDY, 1);
        reg_isr_update_irq(s);
    }
}

static bool ams_sat_is_running(AMS_SAT *s)
{
    uint32_t pcsr = s->regs[R_REG_PCSR_CONTROL];

    pcsr &= R_REG_PCSR_CONTROL_HOLDSTATE_MASK |
            R_REG_PCSR_CONTROL_INITSTATE_MASK |
            R_REG_PCSR_CONTROL_PCOMPLETE_MASK;

    return pcsr == R_REG_PCSR_CONTROL_PCOMPLETE_MASK;
}

static uint64_t ams_sat_pcsr_control_prew(RegisterInfo *reg, uint64_t val64)
{
    AMS_SAT *s = XLNX_AMS_SAT(reg->opaque);
    uint32_t wr_mask, new_val, old_val;
    uint32_t to_1s, to_0s;

    /* On register resetting, all behavior is bypassed. */
    if (s->reg_reset) {
        return val64;
    }

    /* Capture mask, because any write to control clears it */
    wr_mask = s->regs[R_REG_PCSR_MASK];
    s->regs[R_REG_PCSR_MASK] = 0;

    /* Control bits blocked by mask cannot be updated */
    old_val = s->regs[R_REG_PCSR_CONTROL];
    new_val = val64;
    new_val = (~wr_mask & old_val) | (wr_mask & new_val);

    /* Save value for applying actions */
    s->regs[R_REG_PCSR_CONTROL] = new_val;

    /* If under test, skip control behavior */
    if (FIELD_EX32(new_val, REG_PCSR_CONTROL, TEST_SAFE)) {
        return new_val;
    }

    /* Apply actions meaningful only when bits changed from 0 to 1 */
    to_1s = ~old_val & new_val;

    if (FIELD_EX32(to_1s, REG_PCSR_CONTROL, INITSTATE)) {
        ams_sat_reset_pulse(s);

        return s->regs[R_REG_PCSR_CONTROL]; /* POR value */
    }

    /* Apply actions meaningful only when bits changed from 1 to 0 */
    to_0s = old_val & ~new_val;
    if (FIELD_EX32(to_0s, REG_PCSR_CONTROL, HOLDSTATE) ||
        FIELD_EX32(to_0s, REG_PCSR_CONTROL, INITSTATE) ||
        FIELD_EX32(to_1s, REG_PCSR_CONTROL, PCOMPLETE)) {
        /* All these bits must be in the right state */
        if (ams_sat_is_running(s)) {
            xlnx_ams_root_sat_config_ready(s->ams_root, s->instance);
        }
    }

    /* Apply actions for bits based on newly written value */
    ams_sat_deep_sleep_update(s, !!FIELD_EX32(new_val,
                                              REG_PCSR_CONTROL, DEEP_SLEEP));

    return s->regs[R_REG_PCSR_CONTROL];
}

static void ams_sat_cal_override_postw(RegisterInfo *reg, uint64_t val64)
{
    AMS_SAT *s = XLNX_AMS_SAT(reg->opaque);
    uint32_t val = val64;
    uint32_t addr;

    static const unsigned r_map[] = {
        [0] = R_SM_GE,
        [1] = R_TSENS_GE,
        [2] = R_UNI_GE,
        [3] = R_BIP_GE,
        [4] = R_SM_LOW_CM_OFFSET,
        [5] = R_SM_HI_CM_OFFSET,
        [6] = R_MOD_OFFSET,
        [7] = R_TSENS_OFFSET,
        [8] = R_UNI_LOW_CM_OFFSET,
        [9] = R_BIP_OFFSET,
        [10] = R_SM_REF_ACTUAL,
        [11] = R_MOD_ACTUAL,
        [12] = R_UNI_ACTUAL,
        [13] = R_BIP_ACTUAL,
        [14] = R_SM_TSENS_TARGET,
        [15] = R_SM_UNI_TARGET,
        [16] = R_SM_BIP_TARGET,
        [17] = R_TSENS_MEAS,
    };

    if (!FIELD_EX32(val, CAL_OVERRIDE, OVERRIDE)
        || !FIELD_EX32(val, CAL_OVERRIDE, ENABLE)) {
        return;
    }

    addr = FIELD_EX32(val, CAL_OVERRIDE, ADDR);
    if (addr >= ARRAY_SIZE(r_map)) {
        return;
    }

    addr = r_map[addr];
    s->regs[addr] = FIELD_EX32(val, CAL_OVERRIDE, DATA);
    return;
}

static const RegisterAccessInfo xlnx_ams_sat_regs_info[] = {
    {   .name = "REG_PCSR_MASK",  .addr = A_REG_PCSR_MASK,
    },{ .name = "REG_PCSR_CONTROL",  .addr = A_REG_PCSR_CONTROL,
        .reset = 0x1fe,
        .pre_write = ams_sat_pcsr_control_prew,
    },{ .name = "REG_PCSR_STATUS",  .addr = A_REG_PCSR_STATUS,
        .reset = 0x1,
        .rsvd = 0xffffc000,
        .ro = 0x3fff,
    },{ .name = "REG_PCSR_LOCK",  .addr = A_REG_PCSR_LOCK,
        .reset = 0x1,
        .rsvd = 0xfffffffe,
    },{ .name = "REG_ITR",  .addr = A_REG_ITR,
        .rsvd = 0xffffff80,
        .pre_write = reg_itr_prew,
    },{ .name = "REG_ISR",  .addr = A_REG_ISR,
        .rsvd = 0xffffff80,
        .w1c = 0x7f,
        .post_write = reg_isr_postw,
    },{ .name = "REG_IMR0",  .addr = A_REG_IMR0,
        .reset = 0x7f,
        .rsvd = 0xffffff80,
        .ro = 0x7f,
    },{ .name = "REG_IER0",  .addr = A_REG_IER0,
        .rsvd = 0xffffff80,
        .pre_write = reg_ier0_prew,
    },{ .name = "REG_IDR0",  .addr = A_REG_IDR0,
        .rsvd = 0xffffff80,
        .pre_write = reg_idr0_prew,
    },{ .name = "REG_IMR1",  .addr = A_REG_IMR1,
        .reset = 0x7f,
        .rsvd = 0xffffff80,
        .ro = 0x7f,
    },{ .name = "REG_IER1",  .addr = A_REG_IER1,
        .rsvd = 0xffffff80,
        .pre_write = reg_ier1_prew,
    },{ .name = "REG_IDR1",  .addr = A_REG_IDR1,
        .rsvd = 0xffffff80,
        .pre_write = reg_idr1_prew,
    },{ .name = "REG_IOR",  .addr = A_REG_IOR,
        .reset = 0xc,
        .rsvd = 0xffffffe0,
    },{ .name = "TOKEN_MNGR",  .addr = A_TOKEN_MNGR,
        .rsvd = 0xfffe0000,
    },{ .name = "ADC_CTRL0",  .addr = A_ADC_CTRL0,
        .rsvd = 0xff000000,
    },{ .name = "ADC_CTRL1",  .addr = A_ADC_CTRL1,
        .rsvd = 0xfffffe00,
    },{ .name = "ADC_CTRL2",  .addr = A_ADC_CTRL2,
        .rsvd = 0xffff8000,
    },{ .name = "SLEEP_WAKE_UP",  .addr = A_SLEEP_WAKE_UP,
        .rsvd = 0xfffffff8,
    },{ .name = "SEQ_CONFIG",  .addr = A_SEQ_CONFIG,
        .rsvd = 0xffffffc0,
    },{ .name = "SYS_SEQ_CONFIG",  .addr = A_SYS_SEQ_CONFIG,
        .rsvd = 0xffffff80,
    },{ .name = "VCCINT_MEAS_CONFIG",  .addr = A_VCCINT_MEAS_CONFIG,
        .rsvd = 0xffffe000,
    },{ .name = "TSENS_MEAS_CONFIG",  .addr = A_TSENS_MEAS_CONFIG,
        .rsvd = 0xfffffe00,
    },{ .name = "VCAL_MEAS_CONFIG",  .addr = A_VCAL_MEAS_CONFIG,
    },{ .name = "TSENS_CAL_MEAS_CONFIG",  .addr = A_TSENS_CAL_MEAS_CONFIG,
        .rsvd = 0xfffffc00,
    },{ .name = "VREF_MODE_UNI",  .addr = A_VREF_MODE_UNI,
        .rsvd = 0xfffffffe,
    },{ .name = "CAL_AVG_SEL",  .addr = A_CAL_AVG_SEL,
        .rsvd = 0xfffffe00,
    },{ .name = "CAL_MODE_TF",  .addr = A_CAL_MODE_TF,
        .rsvd = 0xffe00000,
    },{ .name = "CAL_MOD_TF",  .addr = A_CAL_MOD_TF,
        .rsvd = 0xffffff80,
    },{ .name = "CAL_TSENS_TF",  .addr = A_CAL_TSENS_TF,
        .rsvd = 0xf0000000,
    },{ .name = "CAL_SM_REF_TARGET",  .addr = A_CAL_SM_REF_TARGET,
        .rsvd = 0xffe00000,
    },{ .name = "CAL_SM_BIP_TSENS",  .addr = A_CAL_SM_BIP_TSENS,
        .rsvd = 0xfffffffc,
    },{ .name = "DISABLE_CAL_CLEAR_ON_VREF_ERROR",
        .addr = A_DISABLE_CAL_CLEAR_ON_VREF_ERROR,
        .rsvd = 0xfffffffc,
    },{ .name = "CAL_DATA_BYPASS",  .addr = A_CAL_DATA_BYPASS,
        .rsvd = 0xfffffff8,
    },{ .name = "CAL_OFFSET_DISABLE",  .addr = A_CAL_OFFSET_DISABLE,
        .rsvd = 0xfffffff0,
    },{ .name = "CAL_GAIN_DISABLE",  .addr = A_CAL_GAIN_DISABLE,
        .rsvd = 0xfffffff0,
    },{ .name = "CAL_OVERRIDE",  .addr = A_CAL_OVERRIDE,
        .rsvd = 0xfe000000,
        .post_write = ams_sat_cal_override_postw,
    },{ .name = "GOQ_TEST",  .addr = A_GOQ_TEST,
        .rsvd = 0xfffffff8,
    },{ .name = "DISABLE_REFIF_V2I_BIAS",  .addr = A_DISABLE_REFIF_V2I_BIAS,
        .rsvd = 0xfffffffe,
    },{ .name = "ANA_SPARE_MUX0",  .addr = A_ANA_SPARE_MUX0,
        .rsvd = 0xfffffe00,
    },{ .name = "ANA_SPARE_MUX1",  .addr = A_ANA_SPARE_MUX1,
        .rsvd = 0xfffffff8,
    },{ .name = "FABRIC_IF_CTRL",  .addr = A_FABRIC_IF_CTRL,
        .rsvd = 0xfffffe00,
    },{ .name = "DIGITAL_BYPASS",  .addr = A_DIGITAL_BYPASS,
        .rsvd = 0xffe00000,
    },{ .name = "DEM_CTRL",  .addr = A_DEM_CTRL,
        .rsvd = 0xfffffe00,
    },{ .name = "DFX",  .addr = A_DFX,
        .rsvd = 0xfffffffc,
    },{ .name = "TSENS_BIAS_CTRL",  .addr = A_TSENS_BIAS_CTRL,
        .rsvd = 0xfffffffc,
    },{ .name = "EFUSE_CONFIG0",  .addr = A_EFUSE_CONFIG0,
    },{ .name = "EFUSE_CONFIG1",  .addr = A_EFUSE_CONFIG1,
    },{ .name = "TSENS_DELTA",  .addr = A_TSENS_DELTA,
        .rsvd = 0xfffffffc,
    },{ .name = "ABIST_START",  .addr = A_ABIST_START,
        .rsvd = 0xfffffffe,
    },{ .name = "ABIST_TEST",  .addr = A_ABIST_TEST,
        .rsvd = 0xfffff800,
    },{ .name = "PSRR_CLK_CTRL",  .addr = A_PSRR_CLK_CTRL,
        .reset = 0x3,
        .rsvd = 0xfffffffc,
    },{ .name = "CDC_SEL",  .addr = A_CDC_SEL,
        .rsvd = 0xfffffffe,
    },{ .name = "TEST_SPARE0",  .addr = A_TEST_SPARE0,
        .rsvd = 0xffffe000,
    },{ .name = "TEST_SPARE1",  .addr = A_TEST_SPARE1,
        .rsvd = 0xffffe000,
    },{ .name = "CONFIG_CONTROL",  .addr = A_CONFIG_CONTROL,
        .rsvd = 0xfffffffe,
    },{ .name = "USER_SEQ0",  .addr = A_USER_SEQ0,
    },{ .name = "USER_SEQ1",  .addr = A_USER_SEQ1,
    },{ .name = "USER_SEQ2",  .addr = A_USER_SEQ2,
    },{ .name = "USER_SEQ3",  .addr = A_USER_SEQ3,
    },{ .name = "USER_SEQ4",  .addr = A_USER_SEQ4,
    },{ .name = "USER_SEQ5",  .addr = A_USER_SEQ5,
    },{ .name = "USER_SEQ6",  .addr = A_USER_SEQ6,
    },{ .name = "USER_SEQ7",  .addr = A_USER_SEQ7,
    },{ .name = "MEASURE0_CONFIG",  .addr = A_MEASURE0_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE1_CONFIG",  .addr = A_MEASURE1_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE2_CONFIG",  .addr = A_MEASURE2_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE3_CONFIG",  .addr = A_MEASURE3_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE4_CONFIG",  .addr = A_MEASURE4_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE5_CONFIG",  .addr = A_MEASURE5_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE6_CONFIG",  .addr = A_MEASURE6_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE7_CONFIG",  .addr = A_MEASURE7_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE8_CONFIG",  .addr = A_MEASURE8_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE9_CONFIG",  .addr = A_MEASURE9_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE10_CONFIG",  .addr = A_MEASURE10_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE11_CONFIG",  .addr = A_MEASURE11_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE12_CONFIG",  .addr = A_MEASURE12_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE13_CONFIG",  .addr = A_MEASURE13_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE14_CONFIG",  .addr = A_MEASURE14_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE15_CONFIG",  .addr = A_MEASURE15_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE16_CONFIG",  .addr = A_MEASURE16_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE17_CONFIG",  .addr = A_MEASURE17_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE18_CONFIG",  .addr = A_MEASURE18_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE19_CONFIG",  .addr = A_MEASURE19_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE20_CONFIG",  .addr = A_MEASURE20_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE21_CONFIG",  .addr = A_MEASURE21_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE22_CONFIG",  .addr = A_MEASURE22_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE23_CONFIG",  .addr = A_MEASURE23_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE24_CONFIG",  .addr = A_MEASURE24_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE25_CONFIG",  .addr = A_MEASURE25_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE26_CONFIG",  .addr = A_MEASURE26_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE27_CONFIG",  .addr = A_MEASURE27_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE28_CONFIG",  .addr = A_MEASURE28_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE29_CONFIG",  .addr = A_MEASURE29_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE30_CONFIG",  .addr = A_MEASURE30_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "MEASURE31_CONFIG",  .addr = A_MEASURE31_CONFIG,
        .rsvd = 0xc0000000,
    },{ .name = "EXT_MUX_ADDR0",  .addr = A_EXT_MUX_ADDR0,
    },{ .name = "EXT_MUX_ADDR1",  .addr = A_EXT_MUX_ADDR1,
    },{ .name = "EXT_MUX_EN",  .addr = A_EXT_MUX_EN,
        .rsvd = 0xffff0000,
    },{ .name = "CONFIG_UPDATE_STATUS",  .addr = A_CONFIG_UPDATE_STATUS,
        .rsvd = 0xfffffffe,
        .ro = 0x1,
    },{ .name = "CAL_STATUS",  .addr = A_CAL_STATUS,
        .rsvd = 0xfffffff8,
        .ro = 0x7,
    },{ .name = "CAL_STATUS_DEBUG",  .addr = A_CAL_STATUS_DEBUG,
        .rsvd = 0xffffff80,
        .ro = 0x7f,
    },{ .name = "SM_GE",  .addr = A_SM_GE,
        .rsvd = 0xfffff800,
        .ro = 0x7ff,
    },{ .name = "TSENS_GE",  .addr = A_TSENS_GE,
        .rsvd = 0xfffff800,
        .ro = 0x7ff,
    },{ .name = "UNI_GE",  .addr = A_UNI_GE,
        .rsvd = 0xfffff800,
        .ro = 0x7ff,
    },{ .name = "BIP_GE",  .addr = A_BIP_GE,
        .rsvd = 0xfffff800,
        .ro = 0x7ff,
    },{ .name = "SM_LOW_CM_OFFSET",  .addr = A_SM_LOW_CM_OFFSET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "SM_HI_CM_OFFSET",  .addr = A_SM_HI_CM_OFFSET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "MOD_OFFSET",  .addr = A_MOD_OFFSET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "TSENS_OFFSET",  .addr = A_TSENS_OFFSET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "UNI_LOW_CM_OFFSET",  .addr = A_UNI_LOW_CM_OFFSET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "BIP_OFFSET",  .addr = A_BIP_OFFSET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "SM_REF_ACTUAL",  .addr = A_SM_REF_ACTUAL,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "MOD_ACTUAL",  .addr = A_MOD_ACTUAL,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "UNI_ACTUAL",  .addr = A_UNI_ACTUAL,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "BIP_ACTUAL",  .addr = A_BIP_ACTUAL,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "SM_TSENS_TARGET",  .addr = A_SM_TSENS_TARGET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "SM_UNI_TARGET",  .addr = A_SM_UNI_TARGET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "SM_BIP_TARGET",  .addr = A_SM_BIP_TARGET,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "TSENS_MEAS",  .addr = A_TSENS_MEAS,
        .rsvd = 0xfffc0000,
        .ro = 0x3ffff,
    },{ .name = "ABIST_STATUS",  .addr = A_ABIST_STATUS,
        .rsvd = 0xffffffe0,
        .ro = 0x1f,
    },{ .name = "ANA_SPARE_OUT",  .addr = A_ANA_SPARE_OUT,
        .rsvd = 0xfffffffc,
        .ro = 0x3,
    },{ .name = "DEEP_SLEEP_STATUS",  .addr = A_DEEP_SLEEP_STATUS,
        .rsvd = 0xfffffffe,
        .ro = 0x1,
    }
};

static void ams_sat_reg_write(void *opaque, hwaddr addr, uint64_t data,
                              unsigned size)
{
    RegisterInfoArray *reg_array = opaque;
    AMS_SAT *s = XLNX_AMS_SAT(reg_array->r[0]->opaque);

    /* Enforce write-lock protection */
    if ((addr == A_REG_PCSR_LOCK) && size == 4) {
        if (data == R_REG_PCSR_LOCK_UNLOCK_CODE) {
            data = 0;
        } else {
            data = R_REG_PCSR_LOCK_STATE_MASK;
        }
    } else if (ARRAY_FIELD_EX32(s->regs, REG_PCSR_LOCK, STATE)) {
        info_report("%s: addr:0x%x: PCSR_LOCK engaged! Write discarded!",
                    object_get_canonical_path(OBJECT(s)), (uint32_t)addr);
        return;
    }

    register_write_memory(opaque, addr, data, size);
}

static const MemoryRegionOps xlnx_ams_sat_ops = {
    .read = register_read_memory,
    .write = ams_sat_reg_write,
    .endianness = DEVICE_LITTLE_ENDIAN,
    .valid = {
        .min_access_size = 4,
        .max_access_size = 4,
    },
};

static void xlnx_ams_sat_init(Object *obj)
{
    AMS_SAT *s = XLNX_AMS_SAT(obj);
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    RegisterInfoArray *reg_array;

    memory_region_init(&s->iomem, obj, TYPE_XLNX_AMS_SAT,
                       XLNX_AMS_SAT_R_MAX * 4);
    reg_array =
        register_init_block32(DEVICE(obj), xlnx_ams_sat_regs_info,
                              ARRAY_SIZE(xlnx_ams_sat_regs_info),
                              s->regs_info, s->regs,
                              &xlnx_ams_sat_ops,
                              XLNX_AMS_SAT_ERR_DEBUG,
                              XLNX_AMS_SAT_R_MAX * 4);
    memory_region_add_subregion(&s->iomem,
                                0x0,
                                &reg_array->mem);
    sysbus_init_mmio(sbd, &s->iomem);
    sysbus_init_irq(sbd, &s->irq_0);
    sysbus_init_irq(sbd, &s->irq_1);
}

static bool ams_sat_sensor_enabled(AMS_SAT *s, const xlnx_ams_sensor_t *si)
{
    size_t nr;

    if (!ams_sat_is_running(s)) {
        return false;
    }

    switch (si->meas_id) {
    case XLNX_AMS_SAT_MEAS_TYPE_TSENS:
        return ARRAY_FIELD_EX32(s->regs, SYS_SEQ_CONFIG, TSENS);
    case XLNX_AMS_SAT_MEAS_TYPE_VCCINT:
        return ARRAY_FIELD_EX32(s->regs, SYS_SEQ_CONFIG, VCCINT);
    }

    /*
     * Scan for sensor's inclusion in the measuring sequencer, where
     * each word selects up to 4 sensors.
     */
    assert(si->meas_id <= AMS_SAT_VOLT_MEAS_LAST_SLOT);
    for (nr = R_USER_SEQ0; nr <= R_USER_SEQ7; nr++) {
        uint32_t seq = s->regs[nr];
        size_t i;

        for (i = 0; i < 4; i++, seq >>= USER_SEQ_CH_NEXT_SHIFT) {
            if (SHARED_FIELD_EX32(seq, USER_SEQ_CH_MEAS_ID) == si->meas_id) {
                return true;
            }
            if (SHARED_FIELD_EX32(seq, USER_SEQ_CH_END_OF_SEQ)) {
                return false; /* End of sequencing list */
            }
        }
    }

    /* Voltage sensor excluded from sequencing list */
    return false;
}

static bool ams_sat_fill_sensor_info(AMS_SAT *s, xlnx_ams_sensor_t *si)
{
    uint32_t cfg;

    si->sat = OBJECT(s);

    switch (si->meas_id) {
    case XLNX_AMS_SAT_MEAS_TYPE_TSENS:
        cfg = s->regs[R_TSENS_MEAS_CONFIG];
        si->root_id = FIELD_EX32(cfg, TSENS_MEAS_CONFIG, ADDR_ID);
        si->amux_ctrl = FIELD_EX32(cfg, TSENS_MEAS_CONFIG, SEL_TSENS_OUT);
        si->abus_sw1 = 0;
        si->abus_sw0 = 0;
        si->mode = 0;
        si->meas_bipolar = 1;
        return ams_sat_sensor_enabled(s, si);
    case XLNX_AMS_SAT_MEAS_TYPE_VCCINT:
        cfg = s->regs[R_VCCINT_MEAS_CONFIG];
        si->root_id = FIELD_EX32(cfg, VCCINT_MEAS_CONFIG, ADDR_ID);
        si->amux_ctrl = FIELD_EX32(cfg, VCCINT_MEAS_CONFIG, AMUX_CTRL);
        si->abus_sw1 = 0;
        si->abus_sw0 = 0;
        si->mode = FIELD_EX32(cfg, VCCINT_MEAS_CONFIG, MODE);
        break;
    default:
        assert(si->meas_id <= AMS_SAT_VOLT_MEAS_LAST_SLOT);

        cfg = s->regs[si->meas_id + R_MEASURE0_CONFIG];
        si->root_id = FIELD_EX32(cfg, MEASURE0_CONFIG, ADDR_ID);
        si->amux_ctrl = FIELD_EX32(cfg, MEASURE0_CONFIG, AMUX_CTRL);
        si->abus_sw1 = FIELD_EX32(cfg, MEASURE0_CONFIG, ABUS_SW1);
        si->abus_sw0 = FIELD_EX32(cfg, MEASURE0_CONFIG, ABUS_SW0);
        si->mode = FIELD_EX32(cfg, MEASURE0_CONFIG, MODE);
        break;
    }

    switch (si->mode) {
    case 0:  /* Device supply, always unipolar */
    case 1:  /* User-selected unipolar */
        si->meas_bipolar = 0;
        break;
    case 2:  /* User-selected bipolar */
        si->meas_bipolar = 1;
        break;
    case 3:  /* Not defined yet */
    default:
        si->meas_bipolar = 0;
        break;
    }

    return ams_sat_sensor_enabled(s, si);
}

static gint ams_sat_meas_cfgs_prop_sorter(gconstpointer a, gconstpointer b)
{
    const xlnx_ams_sensor_t *s1 = a, *s2 = b;

    if (s1->root_id < s2->root_id) {
        return -1;
    } else {
        return s1->root_id - s2->root_id;
    }
}

static void ams_sat_meas_cfgs_prop_get(Object *obj, Visitor *v,
                                       const char *name, void *opaque,
                                       Error **errp)
{
    AMS_SAT *s = XLNX_AMS_SAT(obj);
    xlnx_ams_sensor_t info, *si = &info;
    GArray *list;
    GString *str;
    unsigned nr;

    static const char * const polarity[] = { "unipolar", "bipolar" };

    str = g_string_new("root, amux_mode_sw1_sw0(hex), sat-name\n");

    si->meas_id = XLNX_AMS_SAT_MEAS_TYPE_TSENS;
    ams_sat_fill_sensor_info(s, si);
    g_string_append_printf(str, "TEMP_SAT%u, %02x, TSENS\n",
                           si->root_id + 1, si->amux_ctrl);

    si->meas_id = XLNX_AMS_SAT_MEAS_TYPE_VCCINT;
    ams_sat_fill_sensor_info(s, si);
    g_string_append_printf(str, "VCCINT_SAT%u, %02x_%02x, VCCINT %s\n",
                           si->root_id + 1, si->amux_ctrl, si->mode,
                           polarity[!!si->meas_bipolar]);

    list = g_array_new(FALSE, FALSE, sizeof(xlnx_ams_sensor_t));
    for (nr = R_MEASURE0_CONFIG; nr <= R_MEASURE31_CONFIG; nr++) {
        uint32_t val = s->regs[nr];
        unsigned sw1 = FIELD_EX32(val, MEASURE0_CONFIG, ABUS_SW1);
        unsigned sw0 = FIELD_EX32(val, MEASURE0_CONFIG, ABUS_SW0);

        if ((sw1 | sw0) == 0) {
            continue;   /* skip unconfigured entry */
        }

        info.meas_id = nr - R_MEASURE0_CONFIG;
        ams_sat_fill_sensor_info(s, &info);
        g_array_append_val(list, info);
    }
    g_array_sort(list, ams_sat_meas_cfgs_prop_sorter);

    for (nr = 0; nr < list->len; nr++) {
        si = &g_array_index(list, xlnx_ams_sensor_t, nr);
        g_string_append_printf(str, "%u, %02x_%02x_%02x_%02x, MEASURE%u %s\n",
                               si->root_id, si->amux_ctrl, si->mode,
                               si->abus_sw1, si->abus_sw0,
                               si->meas_id, polarity[!!si->meas_bipolar]);
    }
    g_array_free(list, TRUE);

    visit_type_str(v, name, &str->str, errp);
    g_string_free(str, TRUE);
}

static void ams_sat_meas_cfgs_prop_add(ObjectClass *klass)
{
    static const char name[] = "sensor-cfgs";

    object_class_property_add(klass, name,
                              "{root, amux_mode_sw1_sw0, sat-name}:str",
                              ams_sat_meas_cfgs_prop_get,
                              NULL, /* non-settable */
                              NULL, NULL);

    object_class_property_set_description(klass, name,
                                          "Satellite sensor config list");
}

static Property ams_sat_properties[] = {
    /* POR auto-calibration simulation by injecting guest read-only values */
#define AMS_SAT_PROP_CALI_REG(prop, reg) \
    DEFINE_PROP_UINT32(prop, AMS_SAT, regs[R_ ## reg], 0)

    AMS_SAT_PROP_CALI_REG("sm-ge", SM_GE),
    AMS_SAT_PROP_CALI_REG("tsens-ge", TSENS_GE),
    AMS_SAT_PROP_CALI_REG("uni-ge", UNI_GE),
    AMS_SAT_PROP_CALI_REG("bip-ge", BIP_GE),
    AMS_SAT_PROP_CALI_REG("sm-low-cm-offset", SM_LOW_CM_OFFSET),
    AMS_SAT_PROP_CALI_REG("sm-hi-cm-offset", SM_HI_CM_OFFSET),
    AMS_SAT_PROP_CALI_REG("mod-offset", MOD_OFFSET),
    AMS_SAT_PROP_CALI_REG("tsens-offset", TSENS_OFFSET),
    AMS_SAT_PROP_CALI_REG("uni-low-cm-offset", UNI_LOW_CM_OFFSET),
    AMS_SAT_PROP_CALI_REG("bip-offset", BIP_OFFSET),
    AMS_SAT_PROP_CALI_REG("sm-ref-actual", SM_REF_ACTUAL),
    AMS_SAT_PROP_CALI_REG("mod-actual", MOD_ACTUAL),
    AMS_SAT_PROP_CALI_REG("uni-actual", UNI_ACTUAL),
    AMS_SAT_PROP_CALI_REG("bip-actual", BIP_ACTUAL),
    AMS_SAT_PROP_CALI_REG("sm-tsens-target", SM_TSENS_TARGET),
    AMS_SAT_PROP_CALI_REG("sm-uni-target", SM_UNI_TARGET),
    AMS_SAT_PROP_CALI_REG("sm-bip-target", SM_BIP_TARGET),
    AMS_SAT_PROP_CALI_REG("tsens-meas", TSENS_MEAS),
#undef AMS_SAT_PROP_CALI_REG

    DEFINE_PROP_END_OF_LIST(),
};

static const VMStateDescription vmstate_xlnx_ams_sat = {
    .name = TYPE_XLNX_AMS_SAT,
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32_ARRAY(regs, AMS_SAT, XLNX_AMS_SAT_R_MAX),
        VMSTATE_END_OF_LIST(),
    }
};

static void xlnx_ams_sat_class_init(ObjectClass *klass, void *data)
{
    ResettableClass *rc = RESETTABLE_CLASS(klass);
    DeviceClass *dc = DEVICE_CLASS(klass);

    dc->vmsd = &vmstate_xlnx_ams_sat;
    rc->phases.enter = ams_sat_reset_enter;
    rc->phases.hold = ams_sat_reset_hold;
    rc->phases.exit = ams_sat_reset_exit;

    device_class_set_props(dc, ams_sat_properties);
    ams_sat_meas_cfgs_prop_add(klass);
}

void xlnx_ams_sat_instance_set(Object *sat, unsigned instance_id, Object *root)
{
    AMS_SAT *s = XLNX_AMS_SAT(sat);

    s->instance = instance_id;
    s->ams_root = root;
}

bool xlnx_ams_sat_config_by_spec(Object *sat, xlnx_ams_sensor_t *si)
{
    AMS_SAT *s = XLNX_AMS_SAT(sat);
    uint32_t mask = R_MEASURE0_CONFIG_AMUX_CTRL_MASK |
                    R_MEASURE0_CONFIG_ABUS_SW1_MASK |
                    R_MEASURE0_CONFIG_ABUS_SW0_MASK;
    uint32_t key = 0;
    unsigned nr;

    switch (si->meas_id) {
    case XLNX_AMS_SAT_MEAS_TYPE_TSENS:
        return ams_sat_fill_sensor_info(s, si);
    case XLNX_AMS_SAT_MEAS_TYPE_VCCINT:
        return ams_sat_fill_sensor_info(s, si);
    }

    key = FIELD_DP32(key, MEASURE0_CONFIG, AMUX_CTRL, si->amux_ctrl);
    key = FIELD_DP32(key, MEASURE0_CONFIG, ABUS_SW1,  si->abus_sw1);
    key = FIELD_DP32(key, MEASURE0_CONFIG, ABUS_SW0,  si->abus_sw0);

    for (nr = R_MEASURE0_CONFIG; (s->regs[nr] & mask) != key; nr++) {
        if (nr >= R_MEASURE31_CONFIG) {
            si->sat = NULL;
            return false;
        }
    }

    si->meas_id = nr - R_MEASURE0_CONFIG;
    return ams_sat_fill_sensor_info(s, si);
}

bool xlnx_ams_sat_config_by_root_id(Object *sat, xlnx_ams_sensor_t *si)
{
    AMS_SAT *s = XLNX_AMS_SAT(sat);
    uint32_t key = si->root_id;
    uint32_t val;
    unsigned nr;

    si->sat = NULL;

    switch (si->meas_id) {
    case XLNX_AMS_SAT_MEAS_TYPE_TSENS:
        val = s->regs[R_TSENS_MEAS_CONFIG];
        if (FIELD_EX32(val, TSENS_MEAS_CONFIG, ADDR_ID) != key) {
            goto not_found;
        }
        return ams_sat_fill_sensor_info(s, si);
    case XLNX_AMS_SAT_MEAS_TYPE_VCCINT:
        val = s->regs[R_VCCINT_MEAS_CONFIG];
        if (FIELD_EX32(val, VCCINT_MEAS_CONFIG, ADDR_ID) != key) {
            goto not_found;
        }
        return ams_sat_fill_sensor_info(s, si);
    }

    for (nr = R_MEASURE0_CONFIG;
         FIELD_EX32(s->regs[nr], MEASURE0_CONFIG, ADDR_ID) != key; nr++) {
        if (nr >= R_MEASURE31_CONFIG) {
            goto not_found;
        }
    }

    si->meas_id = nr - R_MEASURE0_CONFIG;

    /*
     * Root-id of 0 is same as reset value and thus ambiguous, so
     * consider it not found if the sensor is not selected in the
     * sequencer.
     */
    if (!ams_sat_fill_sensor_info(s, si)) {
        if (si->root_id == 0) {
            goto not_found;
        }

        return false;
    }

    return true;

 not_found:
    nr = si->meas_id;
    memset(si, 0, sizeof(*si));
    si->meas_id = nr;
    si->root_id = key;
    return false;
}

GArray *xlnx_ams_sat_config_list(Object *sat)
{
    AMS_SAT *s = XLNX_AMS_SAT(sat);
    xlnx_ams_sensor_t info;
    GArray *list;
    unsigned nr;

    if (!ams_sat_is_running(s)) {
        return NULL;
    }

    list = g_array_new(FALSE, FALSE, sizeof(xlnx_ams_sensor_t));

    for (nr = R_USER_SEQ0; nr <= R_USER_SEQ7; nr++) {
        uint32_t seq = s->regs[nr];
        size_t i;

        for (i = 0; i < 4; i++, seq >>= USER_SEQ_CH_NEXT_SHIFT) {
            info.meas_id = SHARED_FIELD_EX32(seq, USER_SEQ_CH_MEAS_ID);

            if (info.meas_id <= AMS_SAT_VOLT_MEAS_LAST_SLOT
                && ams_sat_fill_sensor_info(s, &info)) {
                g_array_append_val(list, info);
            }

            if (SHARED_FIELD_EX32(seq, USER_SEQ_CH_END_OF_SEQ)) {
                nr = R_USER_SEQ7; /* Force end of iteration */
                break;
            }
        }
    }

    g_array_sort(list, ams_sat_meas_cfgs_prop_sorter);

    info.meas_id = XLNX_AMS_SAT_MEAS_TYPE_VCCINT;
    if (ams_sat_fill_sensor_info(s, &info)) {
        g_array_append_val(list, info);
    }

    info.meas_id = XLNX_AMS_SAT_MEAS_TYPE_TSENS;
    if (ams_sat_fill_sensor_info(s, &info)) {
        g_array_append_val(list, info);
    }

    return list;
}

static const TypeInfo xlnx_ams_sat_info = {
    .name          = TYPE_XLNX_AMS_SAT,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(AMS_SAT),
    .class_init    = xlnx_ams_sat_class_init,
    .instance_init = xlnx_ams_sat_init,
};

static void xlnx_ams_sat_register_types(void)
{
    type_register_static(&xlnx_ams_sat_info);
}

type_init(xlnx_ams_sat_register_types)
