Hi Vikram,

A few comments below and some suggestions!


On [2023 Apr 24] Mon 23:34:31, Vikram Garhwal wrote:
> The Xilinx Versal CANFD controller is developed based on SocketCAN, QEMU CAN 
> bus
> implementation. Bus connection and socketCAN connection for each CAN module
> can be set through command lines.
> 
> Signed-off-by: Vikram Garhwal <vikram.garh...@amd.com>
> ---
>  hw/net/can/meson.build             |    1 +
>  hw/net/can/trace-events            |    7 +
>  hw/net/can/xlnx-versal-canfd.c     | 2115 ++++++++++++++++++++++++++++
>  include/hw/net/xlnx-versal-canfd.h |   87 ++
>  4 files changed, 2210 insertions(+)
>  create mode 100644 hw/net/can/xlnx-versal-canfd.c
>  create mode 100644 include/hw/net/xlnx-versal-canfd.h
> 
> diff --git a/hw/net/can/meson.build b/hw/net/can/meson.build
> index 8fabbd9ee6..8d85201cb0 100644
> --- a/hw/net/can/meson.build
> +++ b/hw/net/can/meson.build
> @@ -5,3 +5,4 @@ softmmu_ss.add(when: 'CONFIG_CAN_PCI', if_true: 
> files('can_mioe3680_pci.c'))
>  softmmu_ss.add(when: 'CONFIG_CAN_CTUCANFD', if_true: files('ctucan_core.c'))
>  softmmu_ss.add(when: 'CONFIG_CAN_CTUCANFD_PCI', if_true: 
> files('ctucan_pci.c'))
>  softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: 
> files('xlnx-zynqmp-can.c'))
> +softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: 
> files('xlnx-versal-canfd.c'))
> diff --git a/hw/net/can/trace-events b/hw/net/can/trace-events
> index 8346a98ab5..de64ac1b31 100644
> --- a/hw/net/can/trace-events
> +++ b/hw/net/can/trace-events
> @@ -7,3 +7,10 @@ xlnx_can_filter_mask_pre_write(uint8_t filter_num, uint32_t 
> value) "Filter%d MAS
>  xlnx_can_tx_data(uint32_t id, uint8_t dlc, uint8_t db0, uint8_t db1, uint8_t 
> db2, uint8_t db3, uint8_t db4, uint8_t db5, uint8_t db6, uint8_t db7) "Frame: 
> ID: 0x%08x DLC: 0x%02x DATA: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 
> 0x%02x"
>  xlnx_can_rx_data(uint32_t id, uint32_t dlc, uint8_t db0, uint8_t db1, 
> uint8_t db2, uint8_t db3, uint8_t db4, uint8_t db5, uint8_t db6, uint8_t db7) 
> "Frame: ID: 0x%08x DLC: 0x%02x DATA: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 
> 0x%02x 0x%02x 0x%02x"
>  xlnx_can_rx_discard(uint32_t status) "Controller is not enabled for bus 
> communication. Status Register: 0x%08x"
> +
> +# xlnx-versal-canfd.c
> +xlnx_canfd_update_irq(char *path, uint32_t isr, uint32_t ier, uint32_t irq) 
> "%s: ISR: 0x%08x IER: 0x%08x IRQ: 0x%08x"
> +xlnx_canfd_rx_fifo_filter_reject(char *path, uint32_t id, uint8_t dlc) "%s: 
> Frame: ID: 0x%08x DLC: 0x%02x"
> +xlnx_canfd_rx_data(char *path, uint32_t id, uint8_t dlc, uint8_t flags) "%s: 
> Frame: ID: 0x%08x DLC: 0x%02x CANFD Flag: 0x%02x"
> +xlnx_canfd_tx_data(char *path, uint32_t id, uint8_t dlc, uint8_t flgas) "%s: 
> Frame: ID: 0x%08x DLC: 0x%02x CANFD Flag: 0x%02x"
> +xlnx_canfd_reset(char *path, uint32_t val) "%s: Resetting controller with 
> value = 0x%08x"
> diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c
> new file mode 100644
> index 0000000000..fb6fa54698
> --- /dev/null
> +++ b/hw/net/can/xlnx-versal-canfd.c
> @@ -0,0 +1,2115 @@
> +/*
> + * QEMU model of the Xilinx Versal CANFD device.
> + *
> + * This implementation is based on the following datasheet:
> + * https://docs.xilinx.com/v/u/2.0-English/pg223-canfd
> + *
> + * Copyright (c) 2022 AMD Inc.
> + *
> + * Written-by: Vikram Garhwal <vikram.garh...@amd.com>
> + *
> + * Based on QEMU CANFD Device emulation implemented by Jin Yang, Deniz Eren 
> and
> + * Pavel Pisa
> + *
> + * 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/irq.h"
> +#include "hw/register.h"
> +#include "qapi/error.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +#include "qemu/cutils.h"
> +#include "qemu/event_notifier.h"
> +#include "hw/qdev-properties.h"
> +#include "qom/object_interfaces.h"
> +#include "migration/vmstate.h"
> +#include "hw/net/xlnx-versal-canfd.h"
> +#include "trace.h"
> +
> +/*
> + * This is done to avoid the build issues on Windows machines. The ERROR 
> field
> + * of INTERRUPT_STATUS_REGISTER collides with a macro in the Windows build
> + * environment.
> + */
> +#undef ERROR

Suggestion: we can consider renaming the bit to something like ERROR_BIT /
ISR_ERROR / ISR_ERR_BIT and turn the comment "this is the ERROR bit in the ISR
register" if deemed needed (it is only used in 1 place after defining it).


> +
> +REG32(SOFTWARE_RESET_REGISTER, 0x0)
> +    FIELD(SOFTWARE_RESET_REGISTER, CEN, 1, 1)
> +    FIELD(SOFTWARE_RESET_REGISTER, SRST, 0, 1)
> +REG32(MODE_SELECT_REGISTER, 0x4)
> +    FIELD(MODE_SELECT_REGISTER, ITO, 8, 8)
> +    FIELD(MODE_SELECT_REGISTER, ABR, 7, 1)
> +    FIELD(MODE_SELECT_REGISTER, SBR, 6, 1)
> +    FIELD(MODE_SELECT_REGISTER, DPEE, 5, 1)
> +    FIELD(MODE_SELECT_REGISTER, DAR, 4, 1)
> +    FIELD(MODE_SELECT_REGISTER, BRSD, 3, 1)
> +    FIELD(MODE_SELECT_REGISTER, SNOOP, 2, 1)
> +    FIELD(MODE_SELECT_REGISTER, LBACK, 1, 1)
> +    FIELD(MODE_SELECT_REGISTER, SLEEP, 0, 1)
> +REG32(ARBITRATION_PHASE_BAUD_RATE_PRESCALER_REGISTER, 0x8)
> +    FIELD(ARBITRATION_PHASE_BAUD_RATE_PRESCALER_REGISTER, BRP, 0, 8)
> +REG32(ARBITRATION_PHASE_BIT_TIMING_REGISTER, 0xc)
> +    FIELD(ARBITRATION_PHASE_BIT_TIMING_REGISTER, SJW, 16, 7)
> +    FIELD(ARBITRATION_PHASE_BIT_TIMING_REGISTER, TS2, 8, 7)
> +    FIELD(ARBITRATION_PHASE_BIT_TIMING_REGISTER, TS1, 0, 8)
> +REG32(ERROR_COUNTER_REGISTER, 0x10)
> +    FIELD(ERROR_COUNTER_REGISTER, REC, 8, 8)
> +    FIELD(ERROR_COUNTER_REGISTER, TEC, 0, 8)
> +REG32(ERROR_STATUS_REGISTER, 0x14)
> +    FIELD(ERROR_STATUS_REGISTER, F_BERR, 11, 1)
> +    FIELD(ERROR_STATUS_REGISTER, F_STER, 10, 1)
> +    FIELD(ERROR_STATUS_REGISTER, F_FMER, 9, 1)
> +    FIELD(ERROR_STATUS_REGISTER, F_CRCER, 8, 1)
> +    FIELD(ERROR_STATUS_REGISTER, ACKER, 4, 1)
> +    FIELD(ERROR_STATUS_REGISTER, BERR, 3, 1)
> +    FIELD(ERROR_STATUS_REGISTER, STER, 2, 1)
> +    FIELD(ERROR_STATUS_REGISTER, FMER, 1, 1)
> +    FIELD(ERROR_STATUS_REGISTER, CRCER, 0, 1)
> +REG32(STATUS_REGISTER, 0x18)
> +    FIELD(STATUS_REGISTER, TDCV, 16, 7)
> +    FIELD(STATUS_REGISTER, SNOOP, 12, 1)
> +    FIELD(STATUS_REGISTER, BSFR_CONFIG, 10, 1)
> +    FIELD(STATUS_REGISTER, PEE_CONFIG, 9, 1)
> +    FIELD(STATUS_REGISTER, ESTAT, 7, 2)
> +    FIELD(STATUS_REGISTER, ERRWRN, 6, 1)
> +    FIELD(STATUS_REGISTER, BBSY, 5, 1)
> +    FIELD(STATUS_REGISTER, BIDLE, 4, 1)
> +    FIELD(STATUS_REGISTER, NORMAL, 3, 1)
> +    FIELD(STATUS_REGISTER, SLEEP, 2, 1)
> +    FIELD(STATUS_REGISTER, LBACK, 1, 1)
> +    FIELD(STATUS_REGISTER, CONFIG, 0, 1)
> +REG32(INTERRUPT_STATUS_REGISTER, 0x1c)
> +    FIELD(INTERRUPT_STATUS_REGISTER, TXEWMFLL, 31, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, TXEOFLW, 30, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, RXBOFLW_BI, 24, 6)
> +    FIELD(INTERRUPT_STATUS_REGISTER, RXLRM_BI, 18, 6)
> +    FIELD(INTERRUPT_STATUS_REGISTER, RXMNF, 17, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, RXFWMFLL_1, 16, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, RXFOFLW_1, 15, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, TXCRS, 14, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, TXRRS, 13, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, RXFWMFLL, 12, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, WKUP, 11, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, SLP, 10, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, BSOFF, 9, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, ERROR, 8, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, RXFOFLW, 6, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, TSCNT_OFLW, 5, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, RXOK, 4, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, BSFRD, 3, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, PEE, 2, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, TXOK, 1, 1)
> +    FIELD(INTERRUPT_STATUS_REGISTER, ARBLST, 0, 1)
> +REG32(INTERRUPT_ENABLE_REGISTER, 0x20)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ETXEWMFLL, 31, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ETXEOFLW, 30, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ERXMNF, 17, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ERXFWMFLL_1, 16, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ERXFOFLW_1, 15, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ETXCRS, 14, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ETXRRS, 13, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ERXFWMFLL, 12, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, EWKUP, 11, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ESLP, 10, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, EBSOFF, 9, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, EERROR, 8, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ERFXOFLW, 6, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ETSCNT_OFLW, 5, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ERXOK, 4, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, EBSFRD, 3, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, EPEE, 2, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, ETXOK, 1, 1)
> +    FIELD(INTERRUPT_ENABLE_REGISTER, EARBLOST, 0, 1)
> +REG32(INTERRUPT_CLEAR_REGISTER, 0x24)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CTXEWMFLL, 31, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CTXEOFLW, 30, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CRXMNF, 17, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CRXFWMFLL_1, 16, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CRXFOFLW_1, 15, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CTXCRS, 14, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CTXRRS, 13, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CRXFWMFLL, 12, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CWKUP, 11, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CSLP, 10, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CBSOFF, 9, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CERROR, 8, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CRFXOFLW, 6, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CTSCNT_OFLW, 5, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CRXOK, 4, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CBSFRD, 3, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CPEE, 2, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CTXOK, 1, 1)
> +    FIELD(INTERRUPT_CLEAR_REGISTER, CARBLOST, 0, 1)
> +REG32(TIMESTAMP_REGISTER, 0x28)
> +    FIELD(TIMESTAMP_REGISTER, TIMESTAMP_CNT, 16, 16)
> +    FIELD(TIMESTAMP_REGISTER, CTS, 0, 1)
> +REG32(DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER, 0x88)
> +    FIELD(DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER, TDC, 16, 1)
> +    FIELD(DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER, TDCOFF, 8, 6)
> +    FIELD(DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER, DP_BRP, 0, 8)
> +REG32(DATA_PHASE_BIT_TIMING_REGISTER, 0x8c)
> +    FIELD(DATA_PHASE_BIT_TIMING_REGISTER, DP_SJW, 16, 4)
> +    FIELD(DATA_PHASE_BIT_TIMING_REGISTER, DP_TS2, 8, 4)
> +    FIELD(DATA_PHASE_BIT_TIMING_REGISTER, DP_TS1, 0, 5)
> +REG32(TX_BUFFER_READY_REQUEST_REGISTER, 0x90)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR31, 31, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR30, 30, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR29, 29, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR28, 28, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR27, 27, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR26, 26, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR25, 25, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR24, 24, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR23, 23, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR22, 22, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR21, 21, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR20, 20, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR19, 19, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR18, 18, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR17, 17, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR16, 16, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR15, 15, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR14, 14, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR13, 13, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR12, 12, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR11, 11, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR10, 10, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR9, 9, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR8, 8, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR7, 7, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR6, 6, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR5, 5, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR4, 4, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR3, 3, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR2, 2, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR1, 1, 1)
> +    FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR0, 0, 1)
> +REG32(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, 0x94)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS31, 31, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS30, 30, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS29, 29, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS28, 28, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS27, 27, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS26, 26, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS25, 25, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS24, 24, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS23, 23, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS22, 22, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS21, 21, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS20, 20, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS19, 19, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS18, 18, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS17, 17, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS16, 16, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS15, 15, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS14, 14, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS13, 13, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS12, 12, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS11, 11, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS10, 10, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS9, 9, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS8, 8, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS7, 7, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS6, 6, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS5, 5, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS4, 4, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS3, 3, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS2, 2, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS1, 1, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS0, 0, 1)
> +REG32(TX_BUFFER_CANCEL_REQUEST_REGISTER, 0x98)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR31, 31, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR30, 30, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR29, 29, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR28, 28, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR27, 27, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR26, 26, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR25, 25, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR24, 24, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR23, 23, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR22, 22, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR21, 21, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR20, 20, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR19, 19, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR18, 18, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR17, 17, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR16, 16, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR15, 15, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR14, 14, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR13, 13, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR12, 12, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR11, 11, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR10, 10, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR9, 9, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR8, 8, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR7, 7, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR6, 6, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR5, 5, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR4, 4, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR3, 3, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR2, 2, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR1, 1, 1)
> +    FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR0, 0, 1)
> +REG32(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, 0x9c)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS31, 
> 31,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS30, 
> 30,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS29, 
> 29,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS28, 
> 28,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS27, 
> 27,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS26, 
> 26,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS25, 
> 25,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS24, 
> 24,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS23, 
> 23,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS22, 
> 22,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS21, 
> 21,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS20, 
> 20,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS19, 
> 19,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS18, 
> 18,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS17, 
> 17,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS16, 
> 16,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS15, 
> 15,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS14, 
> 14,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS13, 
> 13,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS12, 
> 12,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS11, 
> 11,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS10, 
> 10,
> +            1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS9, 
> 9, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS8, 
> 8, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS7, 
> 7, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS6, 
> 6, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS5, 
> 5, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS4, 
> 4, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS3, 
> 3, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS2, 
> 2, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS1, 
> 1, 1)
> +    FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS0, 
> 0, 1)
> +REG32(TX_EVENT_FIFO_STATUS_REGISTER, 0xa0)
> +    FIELD(TX_EVENT_FIFO_STATUS_REGISTER, TXE_FL, 8, 6)
> +    FIELD(TX_EVENT_FIFO_STATUS_REGISTER, TXE_IRI, 7, 1)
> +    FIELD(TX_EVENT_FIFO_STATUS_REGISTER, TXE_RI, 0, 5)
> +REG32(TX_EVENT_FIFO_WATERMARK_REGISTER, 0xa4)
> +    FIELD(TX_EVENT_FIFO_WATERMARK_REGISTER, TXE_FWM, 0, 5)
> +REG32(ACCEPTANCE_FILTER_CONTROL_REGISTER, 0xe0)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF31, 31, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF30, 30, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF29, 29, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF28, 28, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF27, 27, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF26, 26, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF25, 25, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF24, 24, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF23, 23, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF22, 22, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF21, 21, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF20, 20, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF19, 19, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF18, 18, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF17, 17, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF16, 16, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF15, 15, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF14, 14, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF13, 13, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF12, 12, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF11, 11, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF10, 10, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF9, 9, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF8, 8, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF7, 7, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF6, 6, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF5, 5, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF4, 4, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF3, 3, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF2, 2, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF1, 1, 1)
> +    FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF0, 0, 1)
> +REG32(RX_FIFO_STATUS_REGISTER, 0xe8)
> +    FIELD(RX_FIFO_STATUS_REGISTER, FL_1, 24, 7)
> +    FIELD(RX_FIFO_STATUS_REGISTER, IRI_1, 23, 1)
> +    FIELD(RX_FIFO_STATUS_REGISTER, RI_1, 16, 6)
> +    FIELD(RX_FIFO_STATUS_REGISTER, FL, 8, 7)
> +    FIELD(RX_FIFO_STATUS_REGISTER, IRI, 7, 1)
> +    FIELD(RX_FIFO_STATUS_REGISTER, RI, 0, 6)
> +REG32(RX_FIFO_WATERMARK_REGISTER, 0xec)
> +    FIELD(RX_FIFO_WATERMARK_REGISTER, RXFP, 16, 5)
> +    FIELD(RX_FIFO_WATERMARK_REGISTER, RXFWM_1, 8, 6)
> +    FIELD(RX_FIFO_WATERMARK_REGISTER, RXFWM, 0, 6)
> +REG32(TB_ID_REGISTER, 0x100)
> +    FIELD(TB_ID_REGISTER, ID, 21, 11)
> +    FIELD(TB_ID_REGISTER, SRR_RTR_RRS, 20, 1)
> +    FIELD(TB_ID_REGISTER, IDE, 19, 1)
> +    FIELD(TB_ID_REGISTER, ID_EXT, 1, 18)
> +    FIELD(TB_ID_REGISTER, RTR_RRS, 0, 1)
> +REG32(TB0_DLC_REGISTER, 0x104)
> +    FIELD(TB0_DLC_REGISTER, DLC, 28, 4)
> +    FIELD(TB0_DLC_REGISTER, FDF, 27, 1)
> +    FIELD(TB0_DLC_REGISTER, BRS, 26, 1)
> +    FIELD(TB0_DLC_REGISTER, RSVD2, 25, 1)
> +    FIELD(TB0_DLC_REGISTER, EFC, 24, 1)
> +    FIELD(TB0_DLC_REGISTER, MM, 16, 8)
> +    FIELD(TB0_DLC_REGISTER, RSVD1, 0, 16)
> +REG32(TB_DW0_REGISTER, 0x108)
> +    FIELD(TB_DW0_REGISTER, DATA_BYTES0, 24, 8)
> +    FIELD(TB_DW0_REGISTER, DATA_BYTES1, 16, 8)
> +    FIELD(TB_DW0_REGISTER, DATA_BYTES2, 8, 8)
> +    FIELD(TB_DW0_REGISTER, DATA_BYTES3, 0, 8)
> +REG32(TB_DW1_REGISTER, 0x10c)
> +    FIELD(TB_DW1_REGISTER, DATA_BYTES4, 24, 8)
> +    FIELD(TB_DW1_REGISTER, DATA_BYTES5, 16, 8)
> +    FIELD(TB_DW1_REGISTER, DATA_BYTES6, 8, 8)
> +    FIELD(TB_DW1_REGISTER, DATA_BYTES7, 0, 8)
> +REG32(TB_DW2_REGISTER, 0x110)
> +    FIELD(TB_DW2_REGISTER, DATA_BYTES8, 24, 8)
> +    FIELD(TB_DW2_REGISTER, DATA_BYTES9, 16, 8)
> +    FIELD(TB_DW2_REGISTER, DATA_BYTES10, 8, 8)
> +    FIELD(TB_DW2_REGISTER, DATA_BYTES11, 0, 8)
> +REG32(TB_DW3_REGISTER, 0x114)
> +    FIELD(TB_DW3_REGISTER, DATA_BYTES12, 24, 8)
> +    FIELD(TB_DW3_REGISTER, DATA_BYTES13, 16, 8)
> +    FIELD(TB_DW3_REGISTER, DATA_BYTES14, 8, 8)
> +    FIELD(TB_DW3_REGISTER, DATA_BYTES15, 0, 8)
> +REG32(TB_DW4_REGISTER, 0x118)
> +    FIELD(TB_DW4_REGISTER, DATA_BYTES16, 24, 8)
> +    FIELD(TB_DW4_REGISTER, DATA_BYTES17, 16, 8)
> +    FIELD(TB_DW4_REGISTER, DATA_BYTES18, 8, 8)
> +    FIELD(TB_DW4_REGISTER, DATA_BYTES19, 0, 8)
> +REG32(TB_DW5_REGISTER, 0x11c)
> +    FIELD(TB_DW5_REGISTER, DATA_BYTES20, 24, 8)
> +    FIELD(TB_DW5_REGISTER, DATA_BYTES21, 16, 8)
> +    FIELD(TB_DW5_REGISTER, DATA_BYTES22, 8, 8)
> +    FIELD(TB_DW5_REGISTER, DATA_BYTES23, 0, 8)
> +REG32(TB_DW6_REGISTER, 0x120)
> +    FIELD(TB_DW6_REGISTER, DATA_BYTES24, 24, 8)
> +    FIELD(TB_DW6_REGISTER, DATA_BYTES25, 16, 8)
> +    FIELD(TB_DW6_REGISTER, DATA_BYTES26, 8, 8)
> +    FIELD(TB_DW6_REGISTER, DATA_BYTES27, 0, 8)
> +REG32(TB_DW7_REGISTER, 0x124)
> +    FIELD(TB_DW7_REGISTER, DATA_BYTES28, 24, 8)
> +    FIELD(TB_DW7_REGISTER, DATA_BYTES29, 16, 8)
> +    FIELD(TB_DW7_REGISTER, DATA_BYTES30, 8, 8)
> +    FIELD(TB_DW7_REGISTER, DATA_BYTES31, 0, 8)
> +REG32(TB_DW8_REGISTER, 0x128)
> +    FIELD(TB_DW8_REGISTER, DATA_BYTES32, 24, 8)
> +    FIELD(TB_DW8_REGISTER, DATA_BYTES33, 16, 8)
> +    FIELD(TB_DW8_REGISTER, DATA_BYTES34, 8, 8)
> +    FIELD(TB_DW8_REGISTER, DATA_BYTES35, 0, 8)
> +REG32(TB_DW9_REGISTER, 0x12c)
> +    FIELD(TB_DW9_REGISTER, DATA_BYTES36, 24, 8)
> +    FIELD(TB_DW9_REGISTER, DATA_BYTES37, 16, 8)
> +    FIELD(TB_DW9_REGISTER, DATA_BYTES38, 8, 8)
> +    FIELD(TB_DW9_REGISTER, DATA_BYTES39, 0, 8)
> +REG32(TB_DW10_REGISTER, 0x130)
> +    FIELD(TB_DW10_REGISTER, DATA_BYTES40, 24, 8)
> +    FIELD(TB_DW10_REGISTER, DATA_BYTES41, 16, 8)
> +    FIELD(TB_DW10_REGISTER, DATA_BYTES42, 8, 8)
> +    FIELD(TB_DW10_REGISTER, DATA_BYTES43, 0, 8)
> +REG32(TB_DW11_REGISTER, 0x134)
> +    FIELD(TB_DW11_REGISTER, DATA_BYTES44, 24, 8)
> +    FIELD(TB_DW11_REGISTER, DATA_BYTES45, 16, 8)
> +    FIELD(TB_DW11_REGISTER, DATA_BYTES46, 8, 8)
> +    FIELD(TB_DW11_REGISTER, DATA_BYTES47, 0, 8)
> +REG32(TB_DW12_REGISTER, 0x138)
> +    FIELD(TB_DW12_REGISTER, DATA_BYTES48, 24, 8)
> +    FIELD(TB_DW12_REGISTER, DATA_BYTES49, 16, 8)
> +    FIELD(TB_DW12_REGISTER, DATA_BYTES50, 8, 8)
> +    FIELD(TB_DW12_REGISTER, DATA_BYTES51, 0, 8)
> +REG32(TB_DW13_REGISTER, 0x13c)
> +    FIELD(TB_DW13_REGISTER, DATA_BYTES52, 24, 8)
> +    FIELD(TB_DW13_REGISTER, DATA_BYTES53, 16, 8)
> +    FIELD(TB_DW13_REGISTER, DATA_BYTES54, 8, 8)
> +    FIELD(TB_DW13_REGISTER, DATA_BYTES55, 0, 8)
> +REG32(TB_DW14_REGISTER, 0x140)
> +    FIELD(TB_DW14_REGISTER, DATA_BYTES56, 24, 8)
> +    FIELD(TB_DW14_REGISTER, DATA_BYTES57, 16, 8)
> +    FIELD(TB_DW14_REGISTER, DATA_BYTES58, 8, 8)
> +    FIELD(TB_DW14_REGISTER, DATA_BYTES59, 0, 8)
> +REG32(TB_DW15_REGISTER, 0x144)
> +    FIELD(TB_DW15_REGISTER, DATA_BYTES60, 24, 8)
> +    FIELD(TB_DW15_REGISTER, DATA_BYTES61, 16, 8)
> +    FIELD(TB_DW15_REGISTER, DATA_BYTES62, 8, 8)
> +    FIELD(TB_DW15_REGISTER, DATA_BYTES63, 0, 8)
> +REG32(AFMR_REGISTER, 0xa00)
> +    FIELD(AFMR_REGISTER, AMID, 21, 11)
> +    FIELD(AFMR_REGISTER, AMSRR, 20, 1)
> +    FIELD(AFMR_REGISTER, AMIDE, 19, 1)
> +    FIELD(AFMR_REGISTER, AMID_EXT, 1, 18)
> +    FIELD(AFMR_REGISTER, AMRTR, 0, 1)
> +REG32(AFIR_REGISTER, 0xa04)
> +    FIELD(AFIR_REGISTER, AIID, 21, 11)
> +    FIELD(AFIR_REGISTER, AISRR, 20, 1)
> +    FIELD(AFIR_REGISTER, AIIDE, 19, 1)
> +    FIELD(AFIR_REGISTER, AIID_EXT, 1, 18)
> +    FIELD(AFIR_REGISTER, AIRTR, 0, 1)
> +REG32(TXE_FIFO_TB_ID_REGISTER, 0x2000)
> +    FIELD(TXE_FIFO_TB_ID_REGISTER, ID, 21, 11)
> +    FIELD(TXE_FIFO_TB_ID_REGISTER, SRR_RTR_RRS, 20, 1)
> +    FIELD(TXE_FIFO_TB_ID_REGISTER, IDE, 19, 1)
> +    FIELD(TXE_FIFO_TB_ID_REGISTER, ID_EXT, 1, 18)
> +    FIELD(TXE_FIFO_TB_ID_REGISTER, RTR_RRS, 0, 1)
> +REG32(TXE_FIFO_TB_DLC_REGISTER, 0x2004)
> +    FIELD(TXE_FIFO_TB_DLC_REGISTER, DLC, 28, 4)
> +    FIELD(TXE_FIFO_TB_DLC_REGISTER, FDF, 27, 1)
> +    FIELD(TXE_FIFO_TB_DLC_REGISTER, BRS, 26, 1)
> +    FIELD(TXE_FIFO_TB_DLC_REGISTER, ET, 24, 2)
> +    FIELD(TXE_FIFO_TB_DLC_REGISTER, MM, 16, 8)
> +    FIELD(TXE_FIFO_TB_DLC_REGISTER, TIMESTAMP, 0, 16)
> +REG32(RB_ID_REGISTER, 0x2100)
> +    FIELD(RB_ID_REGISTER, ID, 21, 11)
> +    FIELD(RB_ID_REGISTER, SRR_RTR_RRS, 20, 1)
> +    FIELD(RB_ID_REGISTER, IDE, 19, 1)
> +    FIELD(RB_ID_REGISTER, ID_EXT, 1, 18)
> +    FIELD(RB_ID_REGISTER, RTR_RRS, 0, 1)
> +REG32(RB_DLC_REGISTER, 0x2104)
> +    FIELD(RB_DLC_REGISTER, DLC, 28, 4)
> +    FIELD(RB_DLC_REGISTER, FDF, 27, 1)
> +    FIELD(RB_DLC_REGISTER, BRS, 26, 1)
> +    FIELD(RB_DLC_REGISTER, ESI, 25, 1)
> +    FIELD(RB_DLC_REGISTER, MATCHED_FILTER_INDEX, 16, 5)
> +    FIELD(RB_DLC_REGISTER, TIMESTAMP, 0, 16)
> +REG32(RB_DW0_REGISTER, 0x2108)
> +    FIELD(RB_DW0_REGISTER, DATA_BYTES0, 24, 8)
> +    FIELD(RB_DW0_REGISTER, DATA_BYTES1, 16, 8)
> +    FIELD(RB_DW0_REGISTER, DATA_BYTES2, 8, 8)
> +    FIELD(RB_DW0_REGISTER, DATA_BYTES3, 0, 8)
> +REG32(RB_DW1_REGISTER, 0x210c)
> +    FIELD(RB_DW1_REGISTER, DATA_BYTES4, 24, 8)
> +    FIELD(RB_DW1_REGISTER, DATA_BYTES5, 16, 8)
> +    FIELD(RB_DW1_REGISTER, DATA_BYTES6, 8, 8)
> +    FIELD(RB_DW1_REGISTER, DATA_BYTES7, 0, 8)
> +REG32(RB_DW2_REGISTER, 0x2110)
> +    FIELD(RB_DW2_REGISTER, DATA_BYTES8, 24, 8)
> +    FIELD(RB_DW2_REGISTER, DATA_BYTES9, 16, 8)
> +    FIELD(RB_DW2_REGISTER, DATA_BYTES10, 8, 8)
> +    FIELD(RB_DW2_REGISTER, DATA_BYTES11, 0, 8)
> +REG32(RB_DW3_REGISTER, 0x2114)
> +    FIELD(RB_DW3_REGISTER, DATA_BYTES12, 24, 8)
> +    FIELD(RB_DW3_REGISTER, DATA_BYTES13, 16, 8)
> +    FIELD(RB_DW3_REGISTER, DATA_BYTES14, 8, 8)
> +    FIELD(RB_DW3_REGISTER, DATA_BYTES15, 0, 8)
> +REG32(RB_DW4_REGISTER, 0x2118)
> +    FIELD(RB_DW4_REGISTER, DATA_BYTES16, 24, 8)
> +    FIELD(RB_DW4_REGISTER, DATA_BYTES17, 16, 8)
> +    FIELD(RB_DW4_REGISTER, DATA_BYTES18, 8, 8)
> +    FIELD(RB_DW4_REGISTER, DATA_BYTES19, 0, 8)
> +REG32(RB_DW5_REGISTER, 0x211c)
> +    FIELD(RB_DW5_REGISTER, DATA_BYTES20, 24, 8)
> +    FIELD(RB_DW5_REGISTER, DATA_BYTES21, 16, 8)
> +    FIELD(RB_DW5_REGISTER, DATA_BYTES22, 8, 8)
> +    FIELD(RB_DW5_REGISTER, DATA_BYTES23, 0, 8)
> +REG32(RB_DW6_REGISTER, 0x2120)
> +    FIELD(RB_DW6_REGISTER, DATA_BYTES24, 24, 8)
> +    FIELD(RB_DW6_REGISTER, DATA_BYTES25, 16, 8)
> +    FIELD(RB_DW6_REGISTER, DATA_BYTES26, 8, 8)
> +    FIELD(RB_DW6_REGISTER, DATA_BYTES27, 0, 8)
> +REG32(RB_DW7_REGISTER, 0x2124)
> +    FIELD(RB_DW7_REGISTER, DATA_BYTES28, 24, 8)
> +    FIELD(RB_DW7_REGISTER, DATA_BYTES29, 16, 8)
> +    FIELD(RB_DW7_REGISTER, DATA_BYTES30, 8, 8)
> +    FIELD(RB_DW7_REGISTER, DATA_BYTES31, 0, 8)
> +REG32(RB_DW8_REGISTER, 0x2128)
> +    FIELD(RB_DW8_REGISTER, DATA_BYTES32, 24, 8)
> +    FIELD(RB_DW8_REGISTER, DATA_BYTES33, 16, 8)
> +    FIELD(RB_DW8_REGISTER, DATA_BYTES34, 8, 8)
> +    FIELD(RB_DW8_REGISTER, DATA_BYTES35, 0, 8)
> +REG32(RB_DW9_REGISTER, 0x212c)
> +    FIELD(RB_DW9_REGISTER, DATA_BYTES36, 24, 8)
> +    FIELD(RB_DW9_REGISTER, DATA_BYTES37, 16, 8)
> +    FIELD(RB_DW9_REGISTER, DATA_BYTES38, 8, 8)
> +    FIELD(RB_DW9_REGISTER, DATA_BYTES39, 0, 8)
> +REG32(RB_DW10_REGISTER, 0x2130)
> +    FIELD(RB_DW10_REGISTER, DATA_BYTES40, 24, 8)
> +    FIELD(RB_DW10_REGISTER, DATA_BYTES41, 16, 8)
> +    FIELD(RB_DW10_REGISTER, DATA_BYTES42, 8, 8)
> +    FIELD(RB_DW10_REGISTER, DATA_BYTES43, 0, 8)
> +REG32(RB_DW11_REGISTER, 0x2134)
> +    FIELD(RB_DW11_REGISTER, DATA_BYTES44, 24, 8)
> +    FIELD(RB_DW11_REGISTER, DATA_BYTES45, 16, 8)
> +    FIELD(RB_DW11_REGISTER, DATA_BYTES46, 8, 8)
> +    FIELD(RB_DW11_REGISTER, DATA_BYTES47, 0, 8)
> +REG32(RB_DW12_REGISTER, 0x2138)
> +    FIELD(RB_DW12_REGISTER, DATA_BYTES48, 24, 8)
> +    FIELD(RB_DW12_REGISTER, DATA_BYTES49, 16, 8)
> +    FIELD(RB_DW12_REGISTER, DATA_BYTES50, 8, 8)
> +    FIELD(RB_DW12_REGISTER, DATA_BYTES51, 0, 8)
> +REG32(RB_DW13_REGISTER, 0x213c)
> +    FIELD(RB_DW13_REGISTER, DATA_BYTES52, 24, 8)
> +    FIELD(RB_DW13_REGISTER, DATA_BYTES53, 16, 8)
> +    FIELD(RB_DW13_REGISTER, DATA_BYTES54, 8, 8)
> +    FIELD(RB_DW13_REGISTER, DATA_BYTES55, 0, 8)
> +REG32(RB_DW14_REGISTER, 0x2140)
> +    FIELD(RB_DW14_REGISTER, DATA_BYTES56, 24, 8)
> +    FIELD(RB_DW14_REGISTER, DATA_BYTES57, 16, 8)
> +    FIELD(RB_DW14_REGISTER, DATA_BYTES58, 8, 8)
> +    FIELD(RB_DW14_REGISTER, DATA_BYTES59, 0, 8)
> +REG32(RB_DW15_REGISTER, 0x2144)
> +    FIELD(RB_DW15_REGISTER, DATA_BYTES60, 24, 8)
> +    FIELD(RB_DW15_REGISTER, DATA_BYTES61, 16, 8)
> +    FIELD(RB_DW15_REGISTER, DATA_BYTES62, 8, 8)
> +    FIELD(RB_DW15_REGISTER, DATA_BYTES63, 0, 8)
> +REG32(RB_ID_REGISTER_1, 0x4100)
> +    FIELD(RB_ID_REGISTER_1, ID, 21, 11)
> +    FIELD(RB_ID_REGISTER_1, SRR_RTR_RRS, 20, 1)
> +    FIELD(RB_ID_REGISTER_1, IDE, 19, 1)
> +    FIELD(RB_ID_REGISTER_1, ID_EXT, 1, 18)
> +    FIELD(RB_ID_REGISTER_1, RTR_RRS, 0, 1)
> +REG32(RB_DLC_REGISTER_1, 0x4104)
> +    FIELD(RB_DLC_REGISTER_1, DLC, 28, 4)
> +    FIELD(RB_DLC_REGISTER_1, FDF, 27, 1)
> +    FIELD(RB_DLC_REGISTER_1, BRS, 26, 1)
> +    FIELD(RB_DLC_REGISTER_1, ESI, 25, 1)
> +    FIELD(RB_DLC_REGISTER_1, MATCHED_FILTER_INDEX, 16, 5)
> +    FIELD(RB_DLC_REGISTER_1, TIMESTAMP, 0, 16)
> +REG32(RB0_DW0_REGISTER_1, 0x4108)
> +    FIELD(RB0_DW0_REGISTER_1, DATA_BYTES0, 24, 8)
> +    FIELD(RB0_DW0_REGISTER_1, DATA_BYTES1, 16, 8)
> +    FIELD(RB0_DW0_REGISTER_1, DATA_BYTES2, 8, 8)
> +    FIELD(RB0_DW0_REGISTER_1, DATA_BYTES3, 0, 8)
> +REG32(RB_DW1_REGISTER_1, 0x410c)
> +    FIELD(RB_DW1_REGISTER_1, DATA_BYTES4, 24, 8)
> +    FIELD(RB_DW1_REGISTER_1, DATA_BYTES5, 16, 8)
> +    FIELD(RB_DW1_REGISTER_1, DATA_BYTES6, 8, 8)
> +    FIELD(RB_DW1_REGISTER_1, DATA_BYTES7, 0, 8)
> +REG32(RB_DW2_REGISTER_1, 0x4110)
> +    FIELD(RB_DW2_REGISTER_1, DATA_BYTES8, 24, 8)
> +    FIELD(RB_DW2_REGISTER_1, DATA_BYTES9, 16, 8)
> +    FIELD(RB_DW2_REGISTER_1, DATA_BYTES10, 8, 8)
> +    FIELD(RB_DW2_REGISTER_1, DATA_BYTES11, 0, 8)
> +REG32(RB_DW3_REGISTER_1, 0x4114)
> +    FIELD(RB_DW3_REGISTER_1, DATA_BYTES12, 24, 8)
> +    FIELD(RB_DW3_REGISTER_1, DATA_BYTES13, 16, 8)
> +    FIELD(RB_DW3_REGISTER_1, DATA_BYTES14, 8, 8)
> +    FIELD(RB_DW3_REGISTER_1, DATA_BYTES15, 0, 8)
> +REG32(RB_DW4_REGISTER_1, 0x4118)
> +    FIELD(RB_DW4_REGISTER_1, DATA_BYTES16, 24, 8)
> +    FIELD(RB_DW4_REGISTER_1, DATA_BYTES17, 16, 8)
> +    FIELD(RB_DW4_REGISTER_1, DATA_BYTES18, 8, 8)
> +    FIELD(RB_DW4_REGISTER_1, DATA_BYTES19, 0, 8)
> +REG32(RB_DW5_REGISTER_1, 0x411c)
> +    FIELD(RB_DW5_REGISTER_1, DATA_BYTES20, 24, 8)
> +    FIELD(RB_DW5_REGISTER_1, DATA_BYTES21, 16, 8)
> +    FIELD(RB_DW5_REGISTER_1, DATA_BYTES22, 8, 8)
> +    FIELD(RB_DW5_REGISTER_1, DATA_BYTES23, 0, 8)
> +REG32(RB_DW6_REGISTER_1, 0x4120)
> +    FIELD(RB_DW6_REGISTER_1, DATA_BYTES24, 24, 8)
> +    FIELD(RB_DW6_REGISTER_1, DATA_BYTES25, 16, 8)
> +    FIELD(RB_DW6_REGISTER_1, DATA_BYTES26, 8, 8)
> +    FIELD(RB_DW6_REGISTER_1, DATA_BYTES27, 0, 8)
> +REG32(RB_DW7_REGISTER_1, 0x4124)
> +    FIELD(RB_DW7_REGISTER_1, DATA_BYTES28, 24, 8)
> +    FIELD(RB_DW7_REGISTER_1, DATA_BYTES29, 16, 8)
> +    FIELD(RB_DW7_REGISTER_1, DATA_BYTES30, 8, 8)
> +    FIELD(RB_DW7_REGISTER_1, DATA_BYTES31, 0, 8)
> +REG32(RB_DW8_REGISTER_1, 0x4128)
> +    FIELD(RB_DW8_REGISTER_1, DATA_BYTES32, 24, 8)
> +    FIELD(RB_DW8_REGISTER_1, DATA_BYTES33, 16, 8)
> +    FIELD(RB_DW8_REGISTER_1, DATA_BYTES34, 8, 8)
> +    FIELD(RB_DW8_REGISTER_1, DATA_BYTES35, 0, 8)
> +REG32(RB_DW9_REGISTER_1, 0x412c)
> +    FIELD(RB_DW9_REGISTER_1, DATA_BYTES36, 24, 8)
> +    FIELD(RB_DW9_REGISTER_1, DATA_BYTES37, 16, 8)
> +    FIELD(RB_DW9_REGISTER_1, DATA_BYTES38, 8, 8)
> +    FIELD(RB_DW9_REGISTER_1, DATA_BYTES39, 0, 8)
> +REG32(RB_DW10_REGISTER_1, 0x4130)
> +    FIELD(RB_DW10_REGISTER_1, DATA_BYTES40, 24, 8)
> +    FIELD(RB_DW10_REGISTER_1, DATA_BYTES41, 16, 8)
> +    FIELD(RB_DW10_REGISTER_1, DATA_BYTES42, 8, 8)
> +    FIELD(RB_DW10_REGISTER_1, DATA_BYTES43, 0, 8)
> +REG32(RB_DW11_REGISTER_1, 0x4134)
> +    FIELD(RB_DW11_REGISTER_1, DATA_BYTES44, 24, 8)
> +    FIELD(RB_DW11_REGISTER_1, DATA_BYTES45, 16, 8)
> +    FIELD(RB_DW11_REGISTER_1, DATA_BYTES46, 8, 8)
> +    FIELD(RB_DW11_REGISTER_1, DATA_BYTES47, 0, 8)
> +REG32(RB_DW12_REGISTER_1, 0x4138)
> +    FIELD(RB_DW12_REGISTER_1, DATA_BYTES48, 24, 8)
> +    FIELD(RB_DW12_REGISTER_1, DATA_BYTES49, 16, 8)
> +    FIELD(RB_DW12_REGISTER_1, DATA_BYTES50, 8, 8)
> +    FIELD(RB_DW12_REGISTER_1, DATA_BYTES51, 0, 8)
> +REG32(RB_DW13_REGISTER_1, 0x413c)
> +    FIELD(RB_DW13_REGISTER_1, DATA_BYTES52, 24, 8)
> +    FIELD(RB_DW13_REGISTER_1, DATA_BYTES53, 16, 8)
> +    FIELD(RB_DW13_REGISTER_1, DATA_BYTES54, 8, 8)
> +    FIELD(RB_DW13_REGISTER_1, DATA_BYTES55, 0, 8)
> +REG32(RB_DW14_REGISTER_1, 0x4140)
> +    FIELD(RB_DW14_REGISTER_1, DATA_BYTES56, 24, 8)
> +    FIELD(RB_DW14_REGISTER_1, DATA_BYTES57, 16, 8)
> +    FIELD(RB_DW14_REGISTER_1, DATA_BYTES58, 8, 8)
> +    FIELD(RB_DW14_REGISTER_1, DATA_BYTES59, 0, 8)
> +REG32(RB_DW15_REGISTER_1, 0x4144)
> +    FIELD(RB_DW15_REGISTER_1, DATA_BYTES60, 24, 8)
> +    FIELD(RB_DW15_REGISTER_1, DATA_BYTES61, 16, 8)
> +    FIELD(RB_DW15_REGISTER_1, DATA_BYTES62, 8, 8)
> +    FIELD(RB_DW15_REGISTER_1, DATA_BYTES63, 0, 8)
> +
> +static uint8_t canfd_dlc_array[8] = {8, 12, 16, 20, 24, 32, 48, 64};
> +
> +static void canfd_update_irq(XlnxVersalCANFDState *s)
> +{
> +    unsigned int irq = s->regs[R_INTERRUPT_STATUS_REGISTER] &
> +                        s->regs[R_INTERRUPT_ENABLE_REGISTER];
> +    g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +    /* RX watermark interrupts. */
> +    if (ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, FL) >
> +        ARRAY_FIELD_EX32(s->regs, RX_FIFO_WATERMARK_REGISTER, RXFWM)) {
> +        ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFWMFLL, 1);
> +    }
> +
> +    if (ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, FL_1) >
> +        ARRAY_FIELD_EX32(s->regs, RX_FIFO_WATERMARK_REGISTER, RXFWM_1)) {
> +        ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFWMFLL_1, 1);
> +    }
> +
> +    /* TX watermark interrupt. */
> +    if (ARRAY_FIELD_EX32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_FL) >
> +        ARRAY_FIELD_EX32(s->regs, TX_EVENT_FIFO_WATERMARK_REGISTER, 
> TXE_FWM)) {
> +        ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXEWMFLL, 1);
> +    }
> +
> +    trace_xlnx_canfd_update_irq(path, s->regs[R_INTERRUPT_STATUS_REGISTER],
> +                                s->regs[R_INTERRUPT_ENABLE_REGISTER], irq);
> +
> +    qemu_set_irq(s->irq_canfd_int, irq);
> +}
> +
> +static void canfd_ier_post_write(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +
> +    canfd_update_irq(s);
> +}
> +
> +static uint64_t canfd_icr_pre_write(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    uint32_t val = val64;
> +
> +    s->regs[R_INTERRUPT_STATUS_REGISTER] &= ~val;
> +
> +    /*
> +     * RXBOFLW_BI field is automatically cleared to default if RXBOFLW bit is
> +     * cleared in ISR.
> +     */
> +    if (ARRAY_FIELD_EX32(s->regs, INTERRUPT_STATUS_REGISTER, RXFWMFLL_1)) {
> +        ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXBOFLW_BI, 0);
> +    }
> +
> +    canfd_update_irq(s);
> +
> +    return 0;
> +}
> +
> +static void canfd_config_reset(XlnxVersalCANFDState *s)
> +{
> +
> +    unsigned int i;
> +
> +    /* Reset all the configuration registers. */
> +    for (i = 0; i < R_RX_FIFO_WATERMARK_REGISTER; ++i) {
> +        register_reset(&s->reg_info[i]);
> +    }
> +
> +    canfd_update_irq(s);
> +}
> +
> +static void canfd_config_mode(XlnxVersalCANFDState *s)
> +{
> +    register_reset(&s->reg_info[R_ERROR_COUNTER_REGISTER]);
> +    register_reset(&s->reg_info[R_ERROR_STATUS_REGISTER]);
> +    register_reset(&s->reg_info[R_STATUS_REGISTER]);
> +
> +    /* Put XlnxVersalCANFDState in configuration mode. */
> +    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, CONFIG, 1);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, WKUP, 0);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, SLP, 0);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, BSOFF, 0);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, ERROR, 0);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFOFLW, 0);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFOFLW_1, 0);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 0);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXOK, 0);
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, ARBLST, 0);
> +
> +    /* Clear the time stamp. */
> +    ptimer_transaction_begin(s->canfd_timer);
> +    ptimer_set_count(s->canfd_timer, 0);
> +    ptimer_transaction_commit(s->canfd_timer);
> +
> +    canfd_update_irq(s);
> +}
> +
> +static void update_status_register_mode_bits(XlnxVersalCANFDState *s)
> +{
> +    bool sleep_status = ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SLEEP);
> +    bool sleep_mode = ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SLEEP);
> +    /* Wake up interrupt bit. */
> +    bool wakeup_irq_val = !sleep_mode && sleep_status;
> +    /* Sleep interrupt bit. */
> +    bool sleep_irq_val = sleep_mode && !sleep_status;
> +
> +    /* Clear previous core mode status bits. */
> +    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, LBACK, 0);
> +    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, SLEEP, 0);
> +    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, SNOOP, 0);
> +    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, NORMAL, 0);
> +
> +    /* set current mode bit and generate irqs accordingly. */
> +    if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, LBACK)) {
> +        ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, LBACK, 1);
> +    } else if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SLEEP)) {
> +        ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, SLEEP, 1);
> +        ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, SLP,
> +                         sleep_irq_val);
> +    } else if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SNOOP)) {
> +        ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, SNOOP, 1);
> +    } else {
> +        /* If all bits are zero, XlnxVersalCANFDState is set in normal mode. 
> */
> +        ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, NORMAL, 1);
> +        /* Set wakeup interrupt bit. */
> +        ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, WKUP,
> +                         wakeup_irq_val);
> +    }
> +
> +    /* Put the CANFD in error active state. */
> +    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, ESTAT, 1);
> +
> +    canfd_update_irq(s);
> +}
> +
> +static uint64_t canfd_msr_pre_write(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    uint32_t val = val64;
> +    uint8_t multi_mode = 0;
> +
> +    /*
> +     * Multiple mode set check. This is done to make sure user doesn't set
> +     * multiple modes.
> +     */
> +    multi_mode = FIELD_EX32(val, MODE_SELECT_REGISTER, LBACK) +
> +                 FIELD_EX32(val, MODE_SELECT_REGISTER, SLEEP) +
> +                 FIELD_EX32(val, MODE_SELECT_REGISTER, SNOOP);
> +
> +    if (multi_mode > 1) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "Attempting to configure several 
> modes"
> +                      " simultaneously. One mode will be selected according 
> to"
> +                      " their priority: LBACK > SLEEP > SNOOP.\n");
> +    }
> +
> +    if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN) == 0) {
> +        /* In configuration mode, any mode can be selected. */
> +        s->regs[R_MODE_SELECT_REGISTER] = val;
> +    } else {
> +        bool sleep_mode_bit = FIELD_EX32(val, MODE_SELECT_REGISTER, SLEEP);
> +
> +        ARRAY_FIELD_DP32(s->regs, MODE_SELECT_REGISTER, SLEEP, 
> sleep_mode_bit);
> +
> +        if (FIELD_EX32(val, MODE_SELECT_REGISTER, LBACK)) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "Attempting to set LBACK mode"
> +                          " without setting CEN bit as 0\n");
> +        } else if (FIELD_EX32(val, MODE_SELECT_REGISTER, SNOOP)) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "Attempting to set SNOOP mode"
> +                          " without setting CEN bit as 0\n");
> +        }
> +
> +        update_status_register_mode_bits(s);
> +    }
> +
> +    return s->regs[R_MODE_SELECT_REGISTER];
> +}
> +
> +static void canfd_exit_sleep_mode(XlnxVersalCANFDState *s)
> +{
> +    ARRAY_FIELD_DP32(s->regs, MODE_SELECT_REGISTER, SLEEP, 0);
> +    update_status_register_mode_bits(s);
> +}
> +
> +static void regs2frame(XlnxVersalCANFDState *s, qemu_can_frame *frame,
> +                       uint32_t reg_num)
> +{
> +    uint32_t i = 0;
> +    uint32_t j = 0;
> +    uint32_t val = 0;
> +    uint32_t dlc_reg_val = 0;
> +    uint32_t dlc_value = 0;
> +
> +    /* Check that reg_num should be within TX register space. */
> +    assert(reg_num <= R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE *
> +                                          s->cfg.tx_fifo));
> +
> +    dlc_reg_val = s->regs[reg_num + 1];
> +    dlc_value = FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, DLC);
> +
> +    frame->can_id = s->regs[reg_num];
> +
> +    if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, FDF)) {
> +        /*
> +         * CANFD frame.
> +         * Converting dlc(0 to 15) 4 Byte data to plain length(i.e. 0 to 64)
> +         * 1 Byte data. This is done to make it work with SocketCAN.
> +         * On actual CANFD frame, this value can't be more than 0xF.
> +         * Conversion table for DLC to plain length:
> +         *
> +         *  DLC                        Plain Length
> +         *  0 - 8                      0 - 8
> +         *  9                          9 - 12
> +         *  10                         13 - 16
> +         *  11                         17 - 20
> +         *  12                         21 - 24
> +         *  13                         25 - 32
> +         *  14                         33 - 48
> +         *  15                         49 - 64
> +         */
> +
> +        frame->flags = QEMU_CAN_FRMF_TYPE_FD;
> +
> +        if (dlc_value < 8) {
> +            frame->can_dlc = dlc_value;
> +        } else {
> +            assert((dlc_value - 8) < ARRAY_SIZE(canfd_dlc_array));
> +            frame->can_dlc = canfd_dlc_array[dlc_value - 8];
> +        }
> +    } else {
> +        /*
> +         * FD Format bit not set that means it is a CAN Frame.
> +         * Conversion table for classic CAN:
> +         *
> +         *  DLC                        Plain Length
> +         *  0 - 7                      0 - 7
> +         *  8 - 15                     8
> +         */
> +
> +        if (dlc_value > 8) {
> +            frame->can_dlc = 8;
> +            qemu_log_mask(LOG_GUEST_ERROR, "Maximum DLC value for Classic 
> CAN"
> +                          " frame is 8. Only 8 byte data will be sent.\n");
> +        } else {
> +            frame->can_dlc = dlc_value;
> +        }
> +    }
> +
> +    for (j = 0; j < frame->can_dlc; j++) {
> +        val = 8 * i;
> +
> +        frame->data[j] = extract32(s->regs[reg_num + 2 + (j / 4)], val, 8);
> +        i++;
> +
> +        if (i % 4 == 0) {
> +            i = 0;
> +        }
> +    }
> +}
> +
> +static void process_cancellation_requests(XlnxVersalCANFDState *s)
> +{
> +    uint32_t clear_mask = s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] &
> +                                 
> s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER];
> +
> +    s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] &= ~clear_mask;
> +    s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER] &= ~clear_mask;
> +
> +    canfd_update_irq(s);
> +}
> +
> +static void store_rx_sequential(XlnxVersalCANFDState *s,
> +                                const qemu_can_frame *frame,
> +                                uint32_t fill_level, uint32_t read_index,
> +                                uint32_t store_location, uint8_t rx_fifo,
> +                                bool rx_fifo_id, uint8_t filter_index)
> +{
> +    int i;
> +    bool is_canfd_frame;
> +    uint8_t dlc = frame->can_dlc;
> +    uint8_t rx_reg_num = 0;
> +    uint32_t dlc_reg_val = 0;
> +    uint32_t data_reg_val = 0;
> +
> +    /* Getting RX0/1 fill level */
> +    if ((fill_level) > rx_fifo - 1) {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: RX%d Buffer is full. Discarding 
> the"
> +                      " message\n", path, rx_fifo_id);
> +
> +        /* Set the corresponding RF buffer overflow interrupt. */
> +        if (rx_fifo_id == 0) {
> +            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFOFLW, 1);
> +        } else {
> +            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFOFLW_1, 
> 1);
> +        }
> +    } else {
> +        uint16_t rx_timestamp = CANFD_TIMER_MAX -
> +                                    ptimer_get_count(s->canfd_timer);
> +
> +        if (rx_timestamp == 0xFFFF) {
> +            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TSCNT_OFLW, 
> 1);
> +        } else {
> +            ARRAY_FIELD_DP32(s->regs, TIMESTAMP_REGISTER, TIMESTAMP_CNT,
> +                             rx_timestamp);
> +        }
> +
> +        if (rx_fifo_id == 0) {
> +            ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL,
> +                             fill_level + 1);
> +            assert(store_location <=
> +                              R_RB_ID_REGISTER + (s->cfg.rx0_fifo *
> +                                                  NUM_REGS_PER_MSG_SPACE));
> +        } else {
> +            ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL_1,
> +                             fill_level + 1);
> +            assert(store_location <=
> +                              R_RB_ID_REGISTER_1 + (s->cfg.rx1_fifo *
> +                                                    NUM_REGS_PER_MSG_SPACE));
> +        }
> +
> +        s->regs[store_location] = frame->can_id;
> +
> +        dlc = frame->can_dlc;
> +
> +        if (frame->flags == QEMU_CAN_FRMF_TYPE_FD) {
> +            is_canfd_frame = true;
> +
> +            /* Store dlc value in Xilinx specific format. */
> +            for (i = 0; i < ARRAY_SIZE(canfd_dlc_array); i++) {
> +                if (canfd_dlc_array[i] == frame->can_dlc) {
> +                    dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, 8 + i);
> +                }
> +            }
> +        } else {
> +            is_canfd_frame = false;
> +
> +            if (frame->can_dlc > 8) {
> +                dlc = 8;
> +            }
> +
> +            dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, dlc);
> +        }
> +
> +        dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, FDF, is_canfd_frame);
> +        dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, TIMESTAMP, 
> rx_timestamp);
> +        dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, MATCHED_FILTER_INDEX,
> +                                  filter_index);
> +        s->regs[store_location + 1] = dlc_reg_val;
> +
> +        for (i = 0; i < dlc; i++) {
> +            /* Register size is 4 byte but frame->data each is 1 byte. */
> +            switch (i % 4) {
> +            case 0:
> +                rx_reg_num = i / 4;
> +
> +                data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3,
> +                                          frame->data[i]);
> +                break;
> +            case 1:
> +                data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2,
> +                                           frame->data[i]);
> +                break;
> +            case 2:
> +                data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1,
> +                                           frame->data[i]);
> +                break;
> +            case 3:
> +                data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0,
> +                                           frame->data[i]);
> +                /*
> +                 * Last Bytes data which means we have all 4 bytes ready to
> +                 * store in one rx regs.
> +                 */
> +                s->regs[store_location + rx_reg_num + 2] = data_reg_val;
> +                break;
> +            }
> +        }
> +
> +        if (i % 4) {
> +            /*
> +             * In case DLC is not multiplier of 4, data is not saved to RX 
> FIFO
> +             * in above switch case. Store the remaining bytes here.
> +             */
> +            s->regs[store_location + rx_reg_num + 2] = data_reg_val;
> +        }
> +
> +        /* set the interrupt as RXOK. */
> +        ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 1);
> +    }
> +}
> +
> +static void update_rx_sequential(XlnxVersalCANFDState *s,
> +                                 const qemu_can_frame *frame)
> +{
> +    bool filter_pass = false;
> +    uint8_t filter_index = 0;
> +    int i;
> +    int filter_partition = ARRAY_FIELD_EX32(s->regs,
> +                                            RX_FIFO_WATERMARK_REGISTER, 
> RXFP);
> +    uint32_t store_location;
> +    uint32_t fill_level;
> +    uint32_t read_index;
> +    uint8_t store_index = 0;
> +    g_autofree char *path = NULL;
> +    /*
> +     * If all UAF bits are set to 0, then received messages are not stored
> +     * in the RX buffers.
> +     */
> +    if (!s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER]) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "No acceptance filter is set. 
> Received"
> +                      " messages will not be stored.\n");

Thinking about it, perhaps above is not an error after all (theoretically one
could want to temporarily filter out all packages), what do you think?

> +    } else {
> +        uint32_t acceptance_filter_status =
> +                                
> s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER];
> +
> +        for (i = 0; i < 32; i++) {
> +            if (acceptance_filter_status & 0x1) {
> +                uint32_t msg_id_masked = s->regs[R_AFMR_REGISTER + 2 * i] &
> +                                         frame->can_id;
> +                uint32_t afir_id_masked = s->regs[R_AFIR_REGISTER + 2 * i] &
> +                                          s->regs[R_AFMR_REGISTER + 2 * i];
> +                uint16_t std_msg_id_masked = FIELD_EX32(msg_id_masked,
> +                                                        AFIR_REGISTER, AIID);
> +                uint16_t std_afir_id_masked = FIELD_EX32(afir_id_masked,
> +                                                         AFIR_REGISTER, 
> AIID);
> +                uint32_t ext_msg_id_masked = FIELD_EX32(msg_id_masked,
> +                                                        AFIR_REGISTER,
> +                                                        AIID_EXT);
> +                uint32_t ext_afir_id_masked = FIELD_EX32(afir_id_masked,
> +                                                         AFIR_REGISTER,
> +                                                         AIID_EXT);
> +                bool ext_ide = FIELD_EX32(s->regs[R_AFMR_REGISTER + 2 * i],
> +                                          AFMR_REGISTER, AMIDE);
> +
> +                if (std_msg_id_masked == std_afir_id_masked) {
> +                    if (ext_ide) {
> +                        /* Extended message ID message. */
> +                        if (ext_msg_id_masked == ext_afir_id_masked) {
> +                            filter_pass = true;
> +                            filter_index = i;
> +
> +                            break;
> +                        }
> +                    } else {
> +                        /* Standard message ID. */
> +                        filter_pass = true;
> +                        filter_index = i;
> +
> +                        break;
> +                    }
> +                }
> +            }
> +            acceptance_filter_status >>= 1;
> +        }
> +    }
> +
> +    if (!filter_pass) {
> +        path = object_get_canonical_path(OBJECT(s));
> +
> +        trace_xlnx_canfd_rx_fifo_filter_reject(path, frame->can_id,
> +                                               frame->can_dlc);
> +    } else {
> +        if (filter_index <= filter_partition) {
> +            fill_level = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, 
> FL);
> +            read_index = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, 
> RI);
> +            store_index = read_index + fill_level;
> +
> +            if (read_index == s->cfg.rx0_fifo - 1) {
> +                /*
> +                 * When ri is s->cfg.rx0_fifo - 1 i.e. max, it goes cyclic 
> that
> +                 * means we reset the ri to 0x0.
> +                 */
> +                read_index = 0;
> +                ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI,
> +                                 read_index);
> +            }
> +
> +            if (store_index > s->cfg.rx0_fifo - 1) {
> +                store_index -= s->cfg.rx0_fifo - 1;
> +            }
> +
> +            store_location = R_RB_ID_REGISTER +
> +                          (store_index * NUM_REGS_PER_MSG_SPACE);
> +
> +            store_rx_sequential(s, frame, fill_level, read_index,
> +                                store_location, s->cfg.rx0_fifo, 0,
> +                                filter_index);
> +        } else {
> +            /* RX 1 fill level message */
> +            fill_level = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER,
> +                                          FL_1);
> +            read_index = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER,
> +                                          RI_1);
> +            store_index = read_index + fill_level;
> +
> +            if (read_index == s->cfg.rx1_fifo - 1) {
> +                /*
> +                 * When ri is s->cfg.rx1_fifo - 1 i.e. max, it goes cyclic 
> that
> +                 * means we reset the ri to 0x0.
> +                 */
> +                read_index = 0;
> +                ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI_1,
> +                                 read_index);
> +            }
> +
> +            if (store_index > s->cfg.rx1_fifo - 1) {
> +                store_index -= s->cfg.rx1_fifo - 1;
> +            }
> +
> +            store_location = R_RB_ID_REGISTER_1 +
> +                          (store_index * NUM_REGS_PER_MSG_SPACE);
> +
> +            store_rx_sequential(s, frame, fill_level, read_index,
> +                                store_location, s->cfg.rx1_fifo, 1,
> +                                filter_index);
> +        }
> +
> +        path = object_get_canonical_path(OBJECT(s));
> +
> +        trace_xlnx_canfd_rx_data(path, frame->can_id, frame->can_dlc,
> +                                 frame->flags);
> +        canfd_update_irq(s);
> +    }
> +}
> +
> +static bool tx_ready_check(XlnxVersalCANFDState *s)
> +{
> +    if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, SRST)) {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempting to transfer data 
> while"
> +                      " XlnxVersalCANFDState is in reset mode\n", path);
> +
> +        return false;
> +    }
> +
> +    if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN) == 0) {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempting to transfer data 
> while"
> +                      " XlnxVersalCANFDState is in configuration mode."
> +                      " Reset the core so operations can start fresh\n",
> +                      path);
> +        return false;
> +    }
> +
> +    if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SNOOP)) {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempting to transfer data 
> while"
> +                      " XlnxVersalCANFDState is in SNOOP MODE\n",
> +                      path);
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
> +static void tx_fifo_stamp(XlnxVersalCANFDState *s, uint32_t tb0_regid)
> +{
> +    /*
> +     * If EFC bit in DLC message is set, this means we will store the
> +     * event of this transmitted message with time stamp.
> +     */
> +    uint32_t dlc_reg_val = 0;
> +
> +    if (FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER, EFC)) {
> +        uint8_t dlc_val = FIELD_EX32(s->regs[tb0_regid + 1], 
> TB0_DLC_REGISTER,
> +                                     DLC);
> +        bool fdf_val = FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER,
> +                                  FDF);
> +        bool brs_val = FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER,
> +                                  BRS);
> +        uint8_t mm_val = FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER,
> +                                    MM);
> +        uint8_t fill_level = ARRAY_FIELD_EX32(s->regs,
> +                                              TX_EVENT_FIFO_STATUS_REGISTER,
> +                                              TXE_FL);
> +        uint8_t read_index = ARRAY_FIELD_EX32(s->regs,
> +                                              TX_EVENT_FIFO_STATUS_REGISTER,
> +                                              TXE_RI);
> +        uint8_t store_index = fill_level + read_index;
> +
> +        if ((fill_level) > s->cfg.tx_fifo - 1) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "TX Event Buffer is full."
> +                          " Discarding the message\n");
> +            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXEOFLW, 1);
> +        } else {
> +            if (read_index == s->cfg.tx_fifo - 1) {
> +                /*
> +                 * When ri is s->cfg.tx_fifo - 1 i.e. max, it goes cyclic 
> that
> +                 * means we reset the ri to 0x0.
> +                 */
> +                read_index = 0;
> +                ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, 
> TXE_RI,
> +                                 read_index);
> +            }
> +
> +            if (store_index > s->cfg.tx_fifo - 1) {
> +                store_index -= s->cfg.tx_fifo - 1;
> +            }
> +
> +            assert(store_index < s->cfg.tx_fifo);
> +
> +            uint32_t tx_event_reg0_id = R_TXE_FIFO_TB_ID_REGISTER +
> +                                        (store_index * 2);
> +
> +            /* Store message ID in TX event register. */
> +            s->regs[tx_event_reg0_id] = s->regs[tb0_regid];
> +
> +            uint16_t tx_timestamp = CANFD_TIMER_MAX -
> +                                            ptimer_get_count(s->canfd_timer);
> +
> +            /* Store DLC with time stamp in DLC regs. */
> +            dlc_reg_val = FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, DLC, 
> dlc_val);
> +            dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, FDF,
> +                                      fdf_val);
> +            dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, BRS,
> +                                      brs_val);
> +            dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, ET, 0x3);
> +            dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, MM, 
> mm_val);
> +            dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, TIMESTAMP,
> +                                      tx_timestamp);
> +            s->regs[tx_event_reg0_id + 1] = dlc_reg_val;
> +
> +            ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_FL,
> +                             fill_level + 1);
> +        }
> +    }
> +}
> +
> +static gint g_cmp_ids(gconstpointer data1, gconstpointer data2)
> +{
> +    tx_ready_reg_info *tx_reg_1 = (tx_ready_reg_info *) data1;
> +    tx_ready_reg_info *tx_reg_2 = (tx_ready_reg_info *) data2;
> +
> +    return tx_reg_1->can_id - tx_reg_2->can_id;
> +}
> +
> +static void free_list(GSList *list)
> +{
> +    GSList *iterator = NULL;
> +
> +    for (iterator = list; iterator != NULL; iterator = iterator->next) {
> +        g_free((tx_ready_reg_info *)iterator->data);
> +    }
> +
> +    g_slist_free(list);
> +
> +    return;
> +}
> +
> +static GSList *prepare_tx_data(XlnxVersalCANFDState *s)
> +{
> +    uint8_t i = 0;
> +    GSList *list = NULL;
> +    uint32_t reg_num = 0;
> +    uint32_t reg_ready = s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER];
> +
> +    /* First find the messages which are ready for transaction. */

s/transaction/transmission/

> +    for (i = 0; i < s->cfg.tx_fifo; i++) {
> +        if (reg_ready) {


We need to add '& 1' on above (for not transmitting packets not ready).

if (reg_ready & 1) {


> +            reg_num = R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE * i);
> +            tx_ready_reg_info *temp = g_new(tx_ready_reg_info, 1);
> +
> +            temp->can_id = s->regs[reg_num];
> +            temp->reg_num = reg_num;
> +            list = g_slist_prepend(list, temp);
> +        }
> +
> +        list = g_slist_sort(list, g_cmp_ids);

Suggestions: we can move above line to after the list prepend (and only call if
needed), and instead of clearing bit by bit below we can do this outside the
for loop:

s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] = 0;
s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER] = 0;

> +        reg_ready >>= 1;
> +        s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] &= ~(1 << i);
> +        s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER] &= ~(1 << i);
> +    }
> +
> +    return list;
> +}
> +
> +static void transfer_data(XlnxVersalCANFDState *s)
> +{
> +    bool canfd_tx = tx_ready_check(s);
> +    GSList *list, *iterator = NULL;
> +
> +    if (!canfd_tx) {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Controller not enabled for data"
> +                      " transfer\n", path);


We need a return here for not transmitting data when tx is not enabled.


> +    }
> +
> +    qemu_can_frame frame;

We can place above declaration with the other declarations in the begining of
the function.

> +
> +    list = prepare_tx_data(s);
> +    if (list == NULL) {
> +        return;
> +    }
> +
> +    for (iterator = list; iterator != NULL; iterator = iterator->next) {
> +        regs2frame(s, &frame,
> +                   ((tx_ready_reg_info *)iterator->data)->reg_num);
> +
> +        if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, LBACK)) {
> +            update_rx_sequential(s, &frame);
> +            tx_fifo_stamp(s, ((tx_ready_reg_info *)iterator->data)->reg_num);
> +
> +            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 1);
> +        } else {
> +            g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +            trace_xlnx_canfd_tx_data(path, frame.can_id, frame.can_dlc,
> +                                     frame.flags);
> +            can_bus_client_send(&s->bus_client, &frame, 1);
> +            tx_fifo_stamp(s,
> +                          ((tx_ready_reg_info *)iterator->data)->reg_num);
> +
> +            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXRRS, 1);
> +
> +            if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SLEEP)) {
> +                canfd_exit_sleep_mode(s);
> +            }
> +        }
> +    }
> +
> +    ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXOK, 1);
> +    free_list(list);
> +
> +    canfd_update_irq(s);
> +}
> +
> +static uint64_t canfd_srr_pre_write(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    uint32_t val = val64;
> +
> +    ARRAY_FIELD_DP32(s->regs, SOFTWARE_RESET_REGISTER, CEN,
> +                     FIELD_EX32(val, SOFTWARE_RESET_REGISTER, CEN));
> +
> +    if (FIELD_EX32(val, SOFTWARE_RESET_REGISTER, SRST)) {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        trace_xlnx_canfd_reset(path, val64);
> +
> +        /* First, core will do software reset then will enter in config 
> mode. */
> +        canfd_config_reset(s);
> +    } else if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN) == 0) 
> {
> +        canfd_config_mode(s);
> +    } else {
> +        /*
> +         * Leave config mode. Now XlnxVersalCANFD core will enter Normal, 
> Sleep,
> +         * snoop or Loopback mode depending upon LBACK, SLEEP, SNOOP register
> +         * states.
> +         */
> +        ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, CONFIG, 0);
> +
> +        ptimer_transaction_begin(s->canfd_timer);
> +        ptimer_set_count(s->canfd_timer, 0);
> +        ptimer_transaction_commit(s->canfd_timer);
> +        update_status_register_mode_bits(s);
> +        transfer_data(s);
> +    }
> +
> +    return s->regs[R_SOFTWARE_RESET_REGISTER];
> +}
> +
> +static uint64_t filter_mask(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    uint32_t reg_idx = (reg->access->addr) / 4;
> +    uint32_t val = val64;
> +    uint32_t filter_offset = (reg_idx - R_AFMR_REGISTER) / 2;
> +
> +    if (!(s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER] &
> +        (1 << filter_offset))) {
> +        s->regs[reg_idx] = val;
> +    } else {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Acceptance filter %d not 
> enabled\n",
> +                      path, filter_offset + 1);
> +    }
> +
> +    return s->regs[reg_idx];
> +}
> +
> +static uint64_t filter_id(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    hwaddr reg_idx = (reg->access->addr) / 4;
> +    uint32_t val = val64;
> +    uint32_t filter_offset = (reg_idx - R_AFIR_REGISTER) / 2;
> +
> +    if (!(s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER] &
> +        (1 << filter_offset))) {
> +        s->regs[reg_idx] = val;
> +    } else {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Acceptance filter %d not 
> enabled\n",
> +                      path, filter_offset + 1);
> +    }
> +
> +    return s->regs[reg_idx];
> +}
> +
> +static uint64_t canfd_tx_fifo_status_prew(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    uint32_t val = val64;
> +    uint8_t read_ind = 0;
> +    uint8_t fill_ind = ARRAY_FIELD_EX32(s->regs, 
> TX_EVENT_FIFO_STATUS_REGISTER,
> +                                        TXE_FL);
> +
> +    if (FIELD_EX32(val, TX_EVENT_FIFO_STATUS_REGISTER, TXE_IRI) && fill_ind) 
> {
> +        read_ind = ARRAY_FIELD_EX32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER,
> +                                    TXE_RI) + 1;
> +
> +        if (read_ind > s->cfg.tx_fifo - 1) {
> +            read_ind = 0;
> +        }
> +
> +        /*
> +         * Increase the read index by 1 and decrease the fill level by 1.
> +         */
> +        ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_RI,
> +                         read_ind);
> +        ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_FL,
> +                         fill_ind - 1);
> +    }
> +
> +    return s->regs[R_TX_EVENT_FIFO_STATUS_REGISTER];
> +}
> +
> +static uint64_t canfd_rx_fifo_status_prew(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    uint32_t val = val64;
> +    uint8_t read_ind = 0;
> +    uint8_t fill_ind = 0;
> +
> +    if (FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, IRI)) {
> +        /* FL index is zero, setting IRI bit has no effect. */
> +        if (FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, FL) != 0) {
> +            read_ind = FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, RI) + 1;
> +
> +            if (read_ind > s->cfg.rx0_fifo - 1) {
> +                read_ind = 0;
> +            }
> +
> +            fill_ind = FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, FL) - 1;
> +
> +            ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI, read_ind);
> +            ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL, fill_ind);
> +        }
> +    }
> +
> +    if (FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, IRI_1)) {
> +        /* FL_1 index is zero, setting IRI_1 bit has no effect. */
> +        if (FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, FL_1) != 0) {
> +            read_ind = FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, RI_1) + 1;
> +
> +            if (read_ind > s->cfg.rx1_fifo - 1) {
> +                read_ind = 0;
> +            }
> +
> +            fill_ind = FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, FL_1) - 1;
> +
> +            ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI_1, 
> read_ind);
> +            ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL_1, 
> fill_ind);
> +        }
> +    }
> +
> +    return s->regs[R_RX_FIFO_STATUS_REGISTER];
> +}
> +
> +static uint64_t canfd_tsr_pre_write(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    uint32_t val = val64;
> +
> +    if (FIELD_EX32(val, TIMESTAMP_REGISTER, CTS)) {
> +        ARRAY_FIELD_DP32(s->regs, TIMESTAMP_REGISTER, TIMESTAMP_CNT, 0);
> +        ptimer_transaction_begin(s->canfd_timer);
> +        ptimer_set_count(s->canfd_timer, 0);
> +        ptimer_transaction_commit(s->canfd_timer);
> +    }
> +
> +    return 0;
> +}
> +
> +static uint64_t canfd_trr_reg_prew(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +
> +    if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SNOOP)) {
> +        g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Controller is in SNOOP mode."
> +                      " tx_ready_register will stay in reset mode\n", path);
> +        return 0;
> +    } else {
> +        return val64;
> +    }
> +}
> +
> +static void canfd_trr_reg_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +
> +    transfer_data(s);
> +}
> +
> +static void canfd_cancel_reg_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +
> +    process_cancellation_requests(s);
> +}
> +
> +static uint64_t canfd_write_check_prew(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
> +    uint32_t val = val64;
> +
> +    if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN) == 0) {
> +        return val;
> +    }
> +    return 0;
> +}
> +
> +static const RegisterAccessInfo canfd_tx_regs[] = {
> +    {   .name = "TB_ID_REGISTER",  .addr = A_TB_ID_REGISTER,
> +    },{ .name = "TB0_DLC_REGISTER",  .addr = A_TB0_DLC_REGISTER,
> +    },{ .name = "TB_DW0_REGISTER",  .addr = A_TB_DW0_REGISTER,
> +    },{ .name = "TB_DW1_REGISTER",  .addr = A_TB_DW1_REGISTER,
> +    },{ .name = "TB_DW2_REGISTER",  .addr = A_TB_DW2_REGISTER,
> +    },{ .name = "TB_DW3_REGISTER",  .addr = A_TB_DW3_REGISTER,
> +    },{ .name = "TB_DW4_REGISTER",  .addr = A_TB_DW4_REGISTER,
> +    },{ .name = "TB_DW5_REGISTER",  .addr = A_TB_DW5_REGISTER,
> +    },{ .name = "TB_DW6_REGISTER",  .addr = A_TB_DW6_REGISTER,
> +    },{ .name = "TB_DW7_REGISTER",  .addr = A_TB_DW7_REGISTER,
> +    },{ .name = "TB_DW8_REGISTER",  .addr = A_TB_DW8_REGISTER,
> +    },{ .name = "TB_DW9_REGISTER",  .addr = A_TB_DW9_REGISTER,
> +    },{ .name = "TB_DW10_REGISTER",  .addr = A_TB_DW10_REGISTER,
> +    },{ .name = "TB_DW11_REGISTER",  .addr = A_TB_DW11_REGISTER,
> +    },{ .name = "TB_DW12_REGISTER",  .addr = A_TB_DW12_REGISTER,
> +    },{ .name = "TB_DW13_REGISTER",  .addr = A_TB_DW13_REGISTER,
> +    },{ .name = "TB_DW14_REGISTER",  .addr = A_TB_DW14_REGISTER,
> +    },{ .name = "TB_DW15_REGISTER",  .addr = A_TB_DW15_REGISTER,
> +    }
> +};
> +
> +static const RegisterAccessInfo canfd_rx0_regs[] = {
> +    {   .name = "RB_ID_REGISTER",  .addr = A_RB_ID_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DLC_REGISTER",  .addr = A_RB_DLC_REGISTER,
> +        .ro = 0xfe1fffff,
> +    },{ .name = "RB_DW0_REGISTER",  .addr = A_RB_DW0_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW1_REGISTER",  .addr = A_RB_DW1_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW2_REGISTER",  .addr = A_RB_DW2_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW3_REGISTER",  .addr = A_RB_DW3_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW4_REGISTER",  .addr = A_RB_DW4_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW5_REGISTER",  .addr = A_RB_DW5_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW6_REGISTER",  .addr = A_RB_DW6_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW7_REGISTER",  .addr = A_RB_DW7_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW8_REGISTER",  .addr = A_RB_DW8_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW9_REGISTER",  .addr = A_RB_DW9_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW10_REGISTER",  .addr = A_RB_DW10_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW11_REGISTER",  .addr = A_RB_DW11_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW12_REGISTER",  .addr = A_RB_DW12_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW13_REGISTER",  .addr = A_RB_DW13_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW14_REGISTER",  .addr = A_RB_DW14_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW15_REGISTER",  .addr = A_RB_DW15_REGISTER,
> +        .ro = 0xffffffff,
> +    }
> +};
> +
> +static const RegisterAccessInfo canfd_rx1_regs[] = {
> +    {   .name = "RB_ID_REGISTER_1",  .addr = A_RB_ID_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DLC_REGISTER_1",  .addr = A_RB_DLC_REGISTER_1,
> +        .ro = 0xfe1fffff,
> +    },{ .name = "RB0_DW0_REGISTER_1",  .addr = A_RB0_DW0_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW1_REGISTER_1",  .addr = A_RB_DW1_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW2_REGISTER_1",  .addr = A_RB_DW2_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW3_REGISTER_1",  .addr = A_RB_DW3_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW4_REGISTER_1",  .addr = A_RB_DW4_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW5_REGISTER_1",  .addr = A_RB_DW5_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW6_REGISTER_1",  .addr = A_RB_DW6_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW7_REGISTER_1",  .addr = A_RB_DW7_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW8_REGISTER_1",  .addr = A_RB_DW8_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW9_REGISTER_1",  .addr = A_RB_DW9_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW10_REGISTER_1",  .addr = A_RB_DW10_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW11_REGISTER_1",  .addr = A_RB_DW11_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW12_REGISTER_1",  .addr = A_RB_DW12_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW13_REGISTER_1",  .addr = A_RB_DW13_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW14_REGISTER_1",  .addr = A_RB_DW14_REGISTER_1,
> +        .ro = 0xffffffff,
> +    },{ .name = "RB_DW15_REGISTER_1",  .addr = A_RB_DW15_REGISTER_1,
> +        .ro = 0xffffffff,
> +    }
> +};
> +
> +/* Acceptance filter registers. */
> +static const RegisterAccessInfo canfd_af_regs[] = {
> +    {   .name = "AFMR_REGISTER",  .addr = A_AFMR_REGISTER,
> +        .pre_write = filter_mask,
> +    },{ .name = "AFIR_REGISTER",  .addr = A_AFIR_REGISTER,
> +        .pre_write = filter_id,
> +    }
> +};
> +
> +static const RegisterAccessInfo canfd_txe_regs[] = {
> +    {   .name = "TXE_FIFO_TB_ID_REGISTER",  .addr = 
> A_TXE_FIFO_TB_ID_REGISTER,
> +        .ro = 0xffffffff,
> +    },{ .name = "TXE_FIFO_TB_DLC_REGISTER",  .addr = 
> A_TXE_FIFO_TB_DLC_REGISTER,
> +        .ro = 0xffffffff,
> +    }
> +};
> +
> +static const RegisterAccessInfo canfd_regs_info[] = {
> +    {   .name = "SOFTWARE_RESET_REGISTER",  .addr = 
> A_SOFTWARE_RESET_REGISTER,
> +        .pre_write = canfd_srr_pre_write,
> +    },{ .name = "MODE_SELECT_REGISTER",  .addr = A_MODE_SELECT_REGISTER,
> +        .pre_write = canfd_msr_pre_write,
> +    },{ .name = "ARBITRATION_PHASE_BAUD_RATE_PRESCALER_REGISTER",
> +        .addr = A_ARBITRATION_PHASE_BAUD_RATE_PRESCALER_REGISTER,
> +        .pre_write = canfd_write_check_prew,
> +    },{ .name = "ARBITRATION_PHASE_BIT_TIMING_REGISTER",
> +        .addr = A_ARBITRATION_PHASE_BIT_TIMING_REGISTER,
> +        .pre_write = canfd_write_check_prew,
> +    },{ .name = "ERROR_COUNTER_REGISTER",  .addr = A_ERROR_COUNTER_REGISTER,
> +        .ro = 0xffff,
> +    },{ .name = "ERROR_STATUS_REGISTER",  .addr = A_ERROR_STATUS_REGISTER,
> +        .w1c = 0xf1f,
> +    },{ .name = "STATUS_REGISTER",  .addr = A_STATUS_REGISTER,
> +        .reset = 0x1,
> +        .ro = 0x7f17ff,
> +    },{ .name = "INTERRUPT_STATUS_REGISTER",
> +        .addr = A_INTERRUPT_STATUS_REGISTER,
> +        .ro = 0xffffff7f,
> +    },{ .name = "INTERRUPT_ENABLE_REGISTER",
> +        .addr = A_INTERRUPT_ENABLE_REGISTER,
> +        .post_write = canfd_ier_post_write,
> +    },{ .name = "INTERRUPT_CLEAR_REGISTER",
> +        .addr = A_INTERRUPT_CLEAR_REGISTER, .pre_write = canfd_icr_pre_write,
> +    },{ .name = "TIMESTAMP_REGISTER",  .addr = A_TIMESTAMP_REGISTER,
> +        .ro = 0xffff0000,
> +        .pre_write = canfd_tsr_pre_write,
> +    },{ .name = "DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER",
> +        .addr = A_DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER,
> +        .pre_write = canfd_write_check_prew,
> +    },{ .name = "DATA_PHASE_BIT_TIMING_REGISTER",
> +        .addr = A_DATA_PHASE_BIT_TIMING_REGISTER,
> +        .pre_write = canfd_write_check_prew,
> +    },{ .name = "TX_BUFFER_READY_REQUEST_REGISTER",
> +        .addr = A_TX_BUFFER_READY_REQUEST_REGISTER,
> +        .pre_write = canfd_trr_reg_prew,
> +        .post_write = canfd_trr_reg_postw,
> +    },{ .name = "INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER",
> +        .addr = A_INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER,
> +    },{ .name = "TX_BUFFER_CANCEL_REQUEST_REGISTER",
> +        .addr = A_TX_BUFFER_CANCEL_REQUEST_REGISTER,
> +        .post_write = canfd_cancel_reg_postw,
> +    },{ .name = "INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER",
> +        .addr = A_INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER,
> +    },{ .name = "TX_EVENT_FIFO_STATUS_REGISTER",
> +        .addr = A_TX_EVENT_FIFO_STATUS_REGISTER,
> +        .ro = 0x3f1f, .pre_write = canfd_tx_fifo_status_prew,
> +    },{ .name = "TX_EVENT_FIFO_WATERMARK_REGISTER",
> +        .addr = A_TX_EVENT_FIFO_WATERMARK_REGISTER,
> +        .reset = 0xf,
> +        .pre_write = canfd_write_check_prew,
> +    },{ .name = "ACCEPTANCE_FILTER_CONTROL_REGISTER",
> +        .addr = A_ACCEPTANCE_FILTER_CONTROL_REGISTER,
> +    },{ .name = "RX_FIFO_STATUS_REGISTER",  .addr = 
> A_RX_FIFO_STATUS_REGISTER,
> +        .ro = 0x7f3f7f3f, .pre_write = canfd_rx_fifo_status_prew,
> +    },{ .name = "RX_FIFO_WATERMARK_REGISTER",
> +        .addr = A_RX_FIFO_WATERMARK_REGISTER,
> +        .reset = 0x1f0f0f,
> +        .pre_write = canfd_write_check_prew,
> +    }
> +};
> +
> +static void xlnx_versal_canfd_ptimer_cb(void *opaque)
> +{
> +    /* No action required on the timer rollover. */
> +}
> +
> +static const MemoryRegionOps canfd_ops = {
> +    .read = register_read_memory,
> +    .write = register_write_memory,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static void canfd_reset(DeviceState *dev)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(dev);
> +    unsigned int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(s->reg_info); ++i) {
> +        register_reset(&s->reg_info[i]);
> +    }
> +
> +    ptimer_transaction_begin(s->canfd_timer);
> +    ptimer_set_count(s->canfd_timer, 0);
> +    ptimer_transaction_commit(s->canfd_timer);
> +}
> +
> +static bool can_xilinx_canfd_receive(CanBusClientState *client)
> +{
> +    XlnxVersalCANFDState *s = container_of(client, XlnxVersalCANFDState,
> +                                           bus_client);
> +
> +    bool reset_state = ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, 
> SRST);
> +    bool can_enabled = ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, 
> CEN);
> +
> +    if (reset_state || !can_enabled) {
> +        return false;
> +    } else {
> +        return true;
> +    }

Suggestion: instead of the if else we can do below:

return !reset_state && can_enabled:

Thanks!

Best regards,
Francisco

> +}
> +
> +static ssize_t canfd_xilinx_receive(CanBusClientState *client,
> +                                    const qemu_can_frame *buf,
> +                                    size_t buf_size)
> +{
> +    XlnxVersalCANFDState *s = container_of(client, XlnxVersalCANFDState,
> +                                           bus_client);
> +    const qemu_can_frame *frame = buf;
> +
> +    assert(buf_size > 0);
> +
> +    if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, LBACK)) {
> +        /*
> +         * XlnxVersalCANFDState will not participate in normal bus 
> communication
> +         * and does not receive any messages transmitted by other CAN nodes.
> +         */
> +        return 1;
> +    }
> +
> +    /* Update the status register that we are receiving message. */
> +    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, BBSY, 1);
> +
> +    if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SNOOP)) {
> +        /* Snoop Mode: Just keep the data. no response back. */
> +        update_rx_sequential(s, frame);
> +    } else {
> +        if ((ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SLEEP))) {
> +            /*
> +             * XlnxVersalCANFDState is in sleep mode. Any data on bus will 
> bring
> +             * it to the wake up state.
> +             */
> +            canfd_exit_sleep_mode(s);
> +        }
> +
> +        update_rx_sequential(s, frame);
> +    }
> +
> +    /* Message processing done. Update the status back to !busy */
> +    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, BBSY, 0);
> +    return 1;
> +}
> +
> +static CanBusClientInfo canfd_xilinx_bus_client_info = {
> +    .can_receive = can_xilinx_canfd_receive,
> +    .receive = canfd_xilinx_receive,
> +};
> +
> +static int xlnx_canfd_connect_to_bus(XlnxVersalCANFDState *s,
> +                                     CanBusState *bus)
> +{
> +    s->bus_client.info = &canfd_xilinx_bus_client_info;
> +
> +    return can_bus_insert_client(bus, &s->bus_client);
> +}
> +
> +#define NUM_REG_PER_AF      ARRAY_SIZE(canfd_af_regs)
> +#define NUM_AF              32
> +#define NUM_REG_PER_TXE     ARRAY_SIZE(canfd_txe_regs)
> +#define NUM_TXE             32
> +
> +static int canfd_populate_regarray(XlnxVersalCANFDState *s,
> +                                  RegisterInfoArray *r_array, int pos,
> +                                  const RegisterAccessInfo *rae,
> +                                  int num_rae)
> +{
> +    int i;
> +
> +    for (i = 0; i < num_rae; i++) {
> +        int index = rae[i].addr / 4;
> +        RegisterInfo *r = &s->reg_info[index];
> +
> +        object_initialize(r, sizeof(*r), TYPE_REGISTER);
> +
> +        *r = (RegisterInfo) {
> +            .data = &s->regs[index],
> +            .data_size = sizeof(uint32_t),
> +            .access = &rae[i],
> +            .opaque = OBJECT(s),
> +        };
> +
> +        r_array->r[i + pos] = r;
> +    }
> +    return i + pos;
> +}
> +
> +static void canfd_create_rai(RegisterAccessInfo *rai_array,
> +                                const RegisterAccessInfo *canfd_regs,
> +                                int template_rai_array_sz,
> +                                int num_template_to_copy)
> +{
> +    int i;
> +    int reg_num;
> +
> +    for (reg_num = 0; reg_num < num_template_to_copy; reg_num++) {
> +        int pos = reg_num * template_rai_array_sz;
> +
> +        memcpy(rai_array + pos, canfd_regs,
> +               template_rai_array_sz * sizeof(RegisterAccessInfo));
> +
> +        for (i = 0; i < template_rai_array_sz; i++) {
> +            const char *name = canfd_regs[i].name;
> +            uint64_t addr = canfd_regs[i].addr;
> +            rai_array[i + pos].name = g_strdup_printf("%s%d", name, reg_num);
> +            rai_array[i + pos].addr = addr + pos * 4;
> +        }
> +    }
> +}
> +
> +static RegisterInfoArray *canfd_create_regarray(XlnxVersalCANFDState *s)
> +{
> +    const char *device_prefix = object_get_typename(OBJECT(s));
> +    uint64_t memory_size = XLNX_VERSAL_CANFD_R_MAX * 4;
> +    int num_regs;
> +    int pos = 0;
> +    RegisterInfoArray *r_array;
> +
> +    num_regs = ARRAY_SIZE(canfd_regs_info) +
> +                s->cfg.tx_fifo * NUM_REGS_PER_MSG_SPACE +
> +                s->cfg.rx0_fifo * NUM_REGS_PER_MSG_SPACE +
> +                NUM_AF * NUM_REG_PER_AF +
> +                NUM_TXE * NUM_REG_PER_TXE;
> +
> +    s->tx_regs = g_new0(RegisterAccessInfo,
> +                        s->cfg.tx_fifo * ARRAY_SIZE(canfd_tx_regs));
> +
> +    canfd_create_rai(s->tx_regs, canfd_tx_regs,
> +                     ARRAY_SIZE(canfd_tx_regs), s->cfg.tx_fifo);
> +
> +    s->rx0_regs = g_new0(RegisterAccessInfo,
> +                         s->cfg.rx0_fifo * ARRAY_SIZE(canfd_rx0_regs));
> +
> +    canfd_create_rai(s->rx0_regs, canfd_rx0_regs,
> +                     ARRAY_SIZE(canfd_rx0_regs), s->cfg.rx0_fifo);
> +
> +    s->af_regs = g_new0(RegisterAccessInfo,
> +                        NUM_AF * ARRAY_SIZE(canfd_af_regs));
> +
> +    canfd_create_rai(s->af_regs, canfd_af_regs,
> +                     ARRAY_SIZE(canfd_af_regs), NUM_AF);
> +
> +    s->txe_regs = g_new0(RegisterAccessInfo,
> +                         NUM_TXE * ARRAY_SIZE(canfd_txe_regs));
> +
> +    canfd_create_rai(s->txe_regs, canfd_txe_regs,
> +                     ARRAY_SIZE(canfd_txe_regs), NUM_TXE);
> +
> +    if (s->cfg.enable_rx_fifo1) {
> +        num_regs += s->cfg.rx1_fifo * NUM_REGS_PER_MSG_SPACE;
> +
> +        s->rx1_regs = g_new0(RegisterAccessInfo,
> +                             s->cfg.rx1_fifo * ARRAY_SIZE(canfd_rx1_regs));
> +
> +        canfd_create_rai(s->rx1_regs, canfd_rx1_regs,
> +                         ARRAY_SIZE(canfd_rx1_regs), s->cfg.rx1_fifo);
> +    }
> +
> +    r_array = g_new0(RegisterInfoArray, 1);
> +    r_array->r = g_new0(RegisterInfo * , num_regs);
> +    r_array->num_elements = num_regs;
> +    r_array->prefix = device_prefix;
> +
> +    pos = canfd_populate_regarray(s, r_array, pos,
> +                                  canfd_regs_info,
> +                                  ARRAY_SIZE(canfd_regs_info));
> +    pos = canfd_populate_regarray(s, r_array, pos,
> +                                  s->tx_regs, s->cfg.tx_fifo *
> +                                  NUM_REGS_PER_MSG_SPACE);
> +    pos = canfd_populate_regarray(s, r_array, pos,
> +                                  s->rx0_regs, s->cfg.rx0_fifo *
> +                                  NUM_REGS_PER_MSG_SPACE);
> +    if (s->cfg.enable_rx_fifo1) {
> +        pos = canfd_populate_regarray(s, r_array, pos,
> +                                      s->rx1_regs, s->cfg.rx1_fifo *
> +                                      NUM_REGS_PER_MSG_SPACE);
> +    }
> +    pos = canfd_populate_regarray(s, r_array, pos,
> +                                  s->af_regs, NUM_AF * NUM_REG_PER_AF);
> +    pos = canfd_populate_regarray(s, r_array, pos,
> +                                  s->txe_regs, NUM_TXE * NUM_REG_PER_TXE);
> +
> +    memory_region_init_io(&r_array->mem, OBJECT(s), &canfd_ops, r_array,
> +                          device_prefix, memory_size);
> +    return r_array;
> +}
> +
> +static void canfd_realize(DeviceState *dev, Error **errp)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(dev);
> +    RegisterInfoArray *reg_array;
> +
> +    reg_array = canfd_create_regarray(s);
> +    memory_region_add_subregion(&s->iomem, 0x00, &reg_array->mem);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
> +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq_canfd_int);
> +
> +    if (s->canfdbus) {
> +        if (xlnx_canfd_connect_to_bus(s, s->canfdbus) < 0) {
> +            g_autofree char *path = object_get_canonical_path(OBJECT(s));
> +
> +            error_setg(errp, "%s: xlnx_canfd_connect_to_bus failed", path);
> +            return;
> +        }
> +
> +    }
> +
> +    /* Allocate a new timer. */
> +    s->canfd_timer = ptimer_init(xlnx_versal_canfd_ptimer_cb, s,
> +                                 PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
> +                                 PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
> +                                 PTIMER_POLICY_NO_IMMEDIATE_RELOAD);
> +
> +    ptimer_transaction_begin(s->canfd_timer);
> +
> +    ptimer_set_freq(s->canfd_timer, s->cfg.ext_clk_freq);
> +    ptimer_set_limit(s->canfd_timer, CANFD_TIMER_MAX, 1);
> +    ptimer_run(s->canfd_timer, 0);
> +    ptimer_transaction_commit(s->canfd_timer);
> +}
> +
> +static void canfd_init(Object *obj)
> +{
> +    XlnxVersalCANFDState *s = XILINX_CANFD(obj);
> +
> +    memory_region_init(&s->iomem, obj, TYPE_XILINX_CANFD,
> +                       XLNX_VERSAL_CANFD_R_MAX * 4);
> +}
> +
> +static const VMStateDescription vmstate_canfd = {
> +    .name = TYPE_XILINX_CANFD,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32_ARRAY(regs, XlnxVersalCANFDState,
> +                             XLNX_VERSAL_CANFD_R_MAX),
> +        VMSTATE_PTIMER(canfd_timer, XlnxVersalCANFDState),
> +        VMSTATE_END_OF_LIST(),
> +    }
> +};
> +
> +static Property canfd_core_properties[] = {
> +    DEFINE_PROP_UINT8("rx-fifo0", XlnxVersalCANFDState, cfg.rx0_fifo, 0x40),
> +    DEFINE_PROP_UINT8("rx-fifo1", XlnxVersalCANFDState, cfg.rx1_fifo, 0x40),
> +    DEFINE_PROP_UINT8("tx-fifo", XlnxVersalCANFDState, cfg.tx_fifo, 0x20),
> +    DEFINE_PROP_BOOL("enable-rx-fifo1", XlnxVersalCANFDState,
> +                     cfg.enable_rx_fifo1, true),
> +    DEFINE_PROP_UINT32("ext_clk_freq", XlnxVersalCANFDState, 
> cfg.ext_clk_freq,
> +                       CANFD_DEFAULT_CLOCK),
> +    DEFINE_PROP_LINK("canfdbus", XlnxVersalCANFDState, canfdbus, 
> TYPE_CAN_BUS,
> +                     CanBusState *),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void canfd_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = canfd_reset;
> +    dc->realize = canfd_realize;
> +    device_class_set_props(dc, canfd_core_properties);
> +    dc->vmsd = &vmstate_canfd;
> +}
> +
> +static const TypeInfo canfd_info = {
> +    .name          = TYPE_XILINX_CANFD,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(XlnxVersalCANFDState),
> +    .class_init    = canfd_class_init,
> +    .instance_init = canfd_init,
> +};
> +
> +static void canfd_register_types(void)
> +{
> +    type_register_static(&canfd_info);
> +}
> +
> +type_init(canfd_register_types)
> diff --git a/include/hw/net/xlnx-versal-canfd.h 
> b/include/hw/net/xlnx-versal-canfd.h
> new file mode 100644
> index 0000000000..544e6545dc
> --- /dev/null
> +++ b/include/hw/net/xlnx-versal-canfd.h
> @@ -0,0 +1,87 @@
> +/*
> + * QEMU model of the Xilinx Versal CANFD Controller.
> + *
> + * Copyright (c) 2022 AMD Inc.
> + *
> + * Written-by: Vikram Garhwal<vikram.garh...@amd.com>
> + * Based on QEMU CANFD Device emulation implemented by Jin Yang, Deniz Eren 
> and
> + * Pavel Pisa.
> + * 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_CANFD_XILINX_H
> +#define HW_CANFD_XILINX_H
> +
> +#include "hw/register.h"
> +#include "hw/ptimer.h"
> +#include "net/can_emu.h"
> +#include "hw/qdev-clock.h"
> +
> +#define TYPE_XILINX_CANFD "xlnx.versal-canfd"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalCANFDState, XILINX_CANFD)
> +
> +#define NUM_REGS_PER_MSG_SPACE 18 /* 1 ID + 1 DLC + 16 Data(DW0 - DW15) 
> regs. */
> +#define MAX_NUM_RX             64
> +#define OFFSET_RX1_DW15        (0x4144 / 4)
> +#define CANFD_TIMER_MAX        0xFFFFUL
> +#define CANFD_DEFAULT_CLOCK    (24 * 1000 * 1000)
> +
> +#define XLNX_VERSAL_CANFD_R_MAX (OFFSET_RX1_DW15 + \
> +                    ((MAX_NUM_RX - 1) * NUM_REGS_PER_MSG_SPACE) + 1)
> +
> +typedef struct XlnxVersalCANFDState {
> +    SysBusDevice            parent_obj;
> +    MemoryRegion            iomem;
> +
> +    qemu_irq                irq_canfd_int;
> +    qemu_irq                irq_addr_err;
> +
> +    RegisterInfo            reg_info[XLNX_VERSAL_CANFD_R_MAX];
> +    RegisterAccessInfo      *tx_regs;
> +    RegisterAccessInfo      *rx0_regs;
> +    RegisterAccessInfo      *rx1_regs;
> +    RegisterAccessInfo      *af_regs;
> +    RegisterAccessInfo      *txe_regs;
> +    RegisterAccessInfo      *rx_mailbox_regs;
> +    RegisterAccessInfo      *af_mask_regs_mailbox;
> +
> +    uint32_t                regs[XLNX_VERSAL_CANFD_R_MAX];
> +
> +    ptimer_state            *canfd_timer;
> +
> +    CanBusClientState       bus_client;
> +    CanBusState             *canfdbus;
> +
> +    struct {
> +        uint8_t             rx0_fifo;
> +        uint8_t             rx1_fifo;
> +        uint8_t             tx_fifo;
> +        bool                enable_rx_fifo1;
> +        uint32_t            ext_clk_freq;
> +   } cfg;
> +
> +} XlnxVersalCANFDState;
> +
> +typedef struct tx_ready_reg_info {
> +    uint32_t can_id;
> +    uint32_t reg_num;
> +} tx_ready_reg_info;
> +
> +#endif
> -- 
> 2.17.1
> 

Reply via email to