qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[QEMU][PATCH 2/5] hw/net/can: Introduce Xilinx Versal CANFD controller


From: Vikram Garhwal
Subject: [QEMU][PATCH 2/5] hw/net/can: Introduce Xilinx Versal CANFD controller
Date: Fri, 9 Sep 2022 23:12:49 -0700

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.

Example for using connecting CANFD0 and CANFD1 to same bus:
    -machine xlnx-versal-virt
    -object can-bus,id=canbus
    -machine canbus0=canbus
    -machine canbus1=canbus

To create virtual CAN on the host machine, please check the QEMU CAN docs:
https://github.com/qemu/qemu/blob/master/docs/can.txt

Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
---
 hw/net/can/meson.build             |    1 +
 hw/net/can/trace-events            |    7 +
 hw/net/can/xlnx-versal-canfd.c     | 2157 ++++++++++++++++++++++++++++
 include/hw/net/xlnx-versal-canfd.h |   92 ++
 4 files changed, 2257 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..7cfc8fee12
--- /dev/null
+++ b/hw/net/can/xlnx-versal-canfd.c
@@ -0,0 +1,2157 @@
+/*
+ * 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.garhwal@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"
+
+/* To avoid the build issues on Windows machines. */
+#undef ERROR
+
+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];
+
+    /* 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);
+    }
+
+    g_autofree char *path = object_get_canonical_path(OBJECT(s));
+
+    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 register. */
+    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 == 0) && sleep_status;
+    /* Sleep interrupt bit. */
+    bool sleep_irq_val = sleep_mode && (sleep_status == 0);
+
+    /* 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 = s->regs[reg_num + 1];
+    uint32_t 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 {
+            frame->can_dlc = canfd_dlc_array[dlc_value - 8];
+        }
+
+        for (i = 0; i < 4 ; i++) {
+            val = 8 * i;
+
+            for (j = 0; j < frame->can_dlc / 4; j++) {
+                frame->data[i + 4 * j] = ((s->regs[reg_num + 2 + j] >> val) &
+                                           0xFF);
+            }
+        }
+    } 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 = dlc_value;
+            dlc_value = 8;
+            qemu_log_mask(LOG_GUEST_ERROR, "Maximum DLC value for Classic CAN"
+                          "  frame can be 8. Only 8 byte data will be 
sent.\n");
+        } else {
+            frame->can_dlc = dlc_value;
+        }
+
+        for (i = 0; i < 4 ; i++) {
+            val = 8 * i;
+
+            for (j = 0; j < dlc_value; j++) {
+                frame->data[i + 4 * j] = ((s->regs[reg_num + 2 + j] >> val) &
+                                           0xFF);
+            }
+        }
+    }
+}
+
+static void process_cancellation_requests(XlnxVersalCANFDState *s)
+{
+    int i;
+    uint32_t val = s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER];
+    uint32_t cancel_val = s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER];
+
+    for (i = 0; i < 32; i++) {
+
+        if ((val & 0x1) && (cancel_val & 0x1)) {
+            s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] &= ~(1 << i);
+            s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER] &= ~(1 << i);
+
+            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXCRS, 1);
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR, "Data Tx going on for requested"
+                          " cancellation bit\n");
+        }
+
+        val >>= 1;
+        cancel_val >>= 1;
+    }
+    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 = 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);
+        } else {
+            ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL_1,
+                             fill_level + 1);
+        }
+        s->regs[store_location] = frame->can_id;
+
+        if (frame->flags == QEMU_CAN_FRMF_TYPE_FD) {
+            is_canfd_frame = true;
+
+            for (i = 0; i < ARRAY_SIZE(canfd_dlc_array); i++) {
+                if (canfd_dlc_array[i] == frame->can_dlc) {
+                    dlc = 8 + i;
+                }
+
+            dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, dlc);
+            }
+        } else {
+            is_canfd_frame = false;
+            if (frame->can_dlc > 8) {
+                dlc = 8;
+            } else {
+                dlc = frame->can_dlc;
+            }
+
+            dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, frame->can_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++) {
+            data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3,
+                                      frame->data[4 * i]);
+            data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2,
+                                       frame->data[4 * i + 1]);
+            data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1,
+                                       frame->data[4 * i + 2]);
+            data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0,
+                                       frame->data[4 * i + 3]);
+            s->regs[store_location + i + 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;
+
+    /*
+     * 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");
+    } 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) {
+        g_autofree char *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);
+            uint8_t 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);
+            uint8_t 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);
+        }
+
+        g_autofree char *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;
+            }
+
+            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 void add_id(txid_list **start, uint32_t can_id, uint32_t reg_num)
+{
+    txid_list *temp = (txid_list *)malloc(sizeof(txid_list));
+
+    if (temp == NULL) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Couldn't allocate memory\n",
+                      __func__);
+        return;
+    }
+
+    temp->can_id = can_id;
+    temp->reg_num = reg_num;
+    temp->next = *start;
+
+    *start = temp;
+}
+
+static void swap_ids(txid_list *first, txid_list *second)
+{
+    uint32_t temp_can_id = first->can_id;
+    uint32_t temp_reg_num = first->reg_num;
+
+    first->can_id = second->can_id;
+    first->reg_num = second->reg_num;
+    second->can_id = temp_can_id;
+    second->reg_num = temp_reg_num;
+}
+
+/* Sort the data to sent in ascending order. */
+static void sort_by_id(XlnxVersalCANFDState *s, txid_list **start)
+{
+    uint8_t i = 0;
+    bool swapped = true;
+
+    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. */
+    for (i = 0; i < s->cfg.tx_fifo; i++) {
+        if (reg_ready) {
+            reg_num = R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE * i);
+            add_id(start, s->regs[reg_num], reg_num);
+        }
+
+        reg_ready >>= 1;
+        s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] &= ~(1 << i);
+        s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER] &= ~(1 << i);
+    }
+
+    /* If no data or only one tx data, no need to sort the ids. */
+    if (*start == NULL || (*start)->next == NULL) {
+        return;
+    }
+
+    txid_list *temp_a, *temp_b = NULL;
+
+    while (swapped) {
+        swapped = false;
+        temp_a = *start;
+
+        while (temp_a->next != temp_b) {
+            if (temp_a->can_id > temp_a->next->can_id) {
+                swap_ids(temp_a, temp_a->next);
+                swapped = true;
+            } else if (temp_a->can_id == temp_a->next->can_id) {
+                /*
+                 * If two IDs are same we sort them by their index. Lowest 
index
+                 * will be transmitted first.
+                 */
+                if (temp_a->reg_num > temp_a->next->reg_num) {
+                    swap_ids(temp_a, temp_a->next);
+                    swapped = true;
+                }
+            }
+
+            temp_a = temp_a->next;
+        }
+
+        temp_b = temp_a;
+    }
+}
+
+static void transfer_data(XlnxVersalCANFDState *s)
+{
+    bool canfd_tx = tx_ready_check(s);
+
+    if (canfd_tx) {
+        qemu_can_frame frame;
+        txid_list *start = NULL;
+
+        sort_by_id(s, &start);
+
+        if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, LBACK)) {
+            while (start != NULL) {
+                regs2frame(s, &frame, start->reg_num);
+                update_rx_sequential(s, &frame);
+                tx_fifo_stamp(s, start->reg_num);
+
+                start = start->next;
+            }
+
+            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 1);
+        } else {
+            while (start != NULL) {
+                regs2frame(s, &frame, start->reg_num);
+
+                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, start->reg_num);
+
+                start = start->next;
+            }
+
+            ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXRRS, 1);
+
+            if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SLEEP)) {
+                canfd_exit_sleep_mode(s);
+            }
+        }
+
+        s->tx_busy_bit = 0;
+
+        ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXOK, 1);
+        free(start);
+    } else {
+          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);
+    }
+
+    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 %dnot 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);
+
+    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: Controller is in reset state.\n",
+                      path);
+        return false;
+    } else 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: Controller is disabled."
+                      " All incoming messages will be discarded\n", path);
+        return false;
+    } else {
+        return true;
+    }
+}
+
+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;
+
+    /* Update the status register that we are receiving message*/
+    ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, BBSY, 1);
+
+    if (buf_size <= 0) {
+        g_autofree char *path = object_get_canonical_path(OBJECT(s));
+
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Error in the data received.\n",
+                      path);
+        return 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.
+         */
+        g_autofree char *path = object_get_canonical_path(OBJECT(s));
+
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Controller  is in loopback mode."
+                      " It will not receive data.\n", path);
+    } else 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;
+
+    if (can_bus_insert_client(bus, &s->bus_client) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+#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((void *)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 void canfd_finalize(Object *obj)
+{
+    XlnxVersalCANFDState *s = XILINX_CANFD(obj);
+    g_free(s->tx_regs);
+    g_free(s->rx0_regs);
+    g_free(s->af_regs);
+    g_free(s->txe_regs);
+    g_free(s->rx1_regs);
+}
+
+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;
+        }
+
+    } else {
+        /* If no bus is set. */
+        g_autofree char *path = object_get_canonical_path(OBJECT(s));
+
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: canfdbus property not set\n", 
path);
+    }
+
+    /* Allocate a new timer. */
+    s->canfd_timer = ptimer_init(xlnx_versal_canfd_ptimer_cb, s,
+                                 PTIMER_POLICY_LEGACY);
+
+    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,
+    .instance_finalize = canfd_finalize,
+};
+
+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..e550f5ccac
--- /dev/null
+++ b/include/hw/net/xlnx-versal-canfd.h
@@ -0,0 +1,92 @@
+/*
+ * QEMU model of the Xilinx Versal CANFD Controller.
+ *
+ * Copyright (c) 2022 AMD Inc.
+ *
+ * Written-by: Vikram Garhwal<vikram.garhwal@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"
+
+#define XILINX_CANFD(obj) \
+     OBJECT_CHECK(XlnxVersalCANFDState, (obj), TYPE_XILINX_CANFD)
+
+#define NUM_REGS_PER_MSG_SPACE 18
+#define MAX_NUM_RX             64
+#define CANFD_TIMER_MAX        0XFFFFUL
+#define CANFD_DEFAULT_CLOCK    (24 * 1000 * 1000)
+
+/* 0x4144/4 + 1 + (64 - 1) * 18 + 1. */
+#define XLNX_VERSAL_CANFD_R_MAX (0x4144 / 4  + \
+                    ((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];
+    uint8_t                 tx_busy_bit;
+    uint8_t                 modes;
+
+    ptimer_state            *canfd_timer;
+
+    CanBusClientState       bus_client;
+    CanBusState             *canfdbus;
+
+    struct {
+        uint8_t             ctrl_idx;
+        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 txid_list {
+    uint32_t can_id;
+    uint32_t reg_num;
+    struct txid_list   *next;
+} txid_list;
+
+#endif
-- 
2.17.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]