diff --git a/decoders/ad5593r/__init__.py b/decoders/ad5593r/__init__.py
new file mode 100644
index 00000000..14d6ee18
--- /dev/null
+++ b/decoders/ad5593r/__init__.py
@@ -0,0 +1,30 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2024 Analog Devices Inc.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see .
+##
+
+'''
+ The Analog Devices AD5593R is a 12-bit ADC/DAC with 8 channels that
+ operates over an I2C interface.
+
+ This decoder stacks on top of the 'i2c' PD and decodes the AD5593R operations.
+
+ Details:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad5593r.pdf
+'''
+
+from .pd import Decoder
\ No newline at end of file
diff --git a/decoders/ad5593r/lists.py b/decoders/ad5593r/lists.py
new file mode 100644
index 00000000..03604a84
--- /dev/null
+++ b/decoders/ad5593r/lists.py
@@ -0,0 +1,636 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2024 Analog Devices Inc.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see .
+##
+
+from dataclasses import dataclass
+from typing import Callable, List, Optional, Union
+
+CONFIG_MODE_BITS_MAP = {
+ 0b0000: "NOP",
+ 0b0010: "ADC_SEQ",
+ 0b0011: "GEN_CTRL_REG",
+ 0b0100: "ADC_CONFIG",
+ 0b0101: "DAC_CONFIG",
+ 0b0110: "PULLDWN_CONFIG",
+ 0b0111: "LDAC_MODE",
+ 0b1000: "GPIO_CONFIG",
+ 0b1001: "GPIO_OUTPUT",
+ 0b1010: "GPIO_INPUT",
+ 0b1011: "PD_REF_CTRL",
+ 0b1100: "GPIO_OPENDRAIN_CONFIG",
+ 0b1101: "IO_TS_CONFIG",
+ 0b1111: "SW_RESET",
+}
+
+REG_SEL_RD_MAP = {
+ 0b0000: "NOP",
+ 0b0010: "ADC_SEQ",
+ 0b0011: "GEN_CTRL_REG",
+ 0b0100: "ADC_CONFIG",
+ 0b0101: "DAC_CONFIG",
+ 0b0110: "PULLDWN_CONFIG",
+ 0b0111: "LDAC mode",
+ 0b1000: "GPIO_CONFIG",
+ 0b1001: "GPIO_OUTPUT",
+ 0b1010: "GPIO_INPUT",
+ 0b1011: "PD_REF_CTRL",
+ 0b1100: "GPIO_OPENDRAIN_CONFIG",
+ 0b1101: "IO_TS_CONFIG",
+}
+
+
+# Utility functions: parse register fields
+def DAC_chn(x: int) -> str:
+ return f"DAC{x}"
+
+
+def ADC_chn(x: int) -> str:
+ return f"ADC{x}"
+
+
+def decimal_to_hex(x: int) -> str:
+ return f"0x{x:02X}"
+
+
+def empty_str(x: int) -> str:
+ return ""
+
+
+def disabled_enabled(x: int) -> str:
+ return ["Disabled", "Enabled"][x]
+
+
+def vref_range(x: int) -> str:
+ return "0V to {text}".format(text=["Vref", "2xVref"][x])
+
+
+def bit_indices(num: int):
+ """Given an number this function extracts the bit indices where the bits are set to 1 and returns them as a string.
+ LSB has index 0.
+ """
+ res = []
+ i = 0
+ while num:
+ if num & 1:
+ res.append(str(i))
+ num >>= 1
+ i += 1
+ if res:
+ return ",".join(res)
+ else:
+ return "NONE"
+
+
+@dataclass
+class Field:
+ start_bit: int
+ width: int
+ name: str
+ parser: Optional[Callable[[int], str]]
+
+
+@dataclass
+class Register:
+ opcode: Union[str, int]
+ name: str
+ fields: List[Field]
+
+
+# Stores register objects which can be retrieved by the opcode as a key.
+# The opcode can be extracted from the raw byte.
+class RegisterDict(dict):
+ def __setitem__(self, opcode, register):
+ if not isinstance(register, Register):
+ raise ValueError("Value must be an instance of Register")
+ super().__setitem__(opcode, register)
+
+ def __getitem__(self, opcode):
+ register = super().__getitem__(opcode)
+ return register
+
+ def get_pointer_byte_register(self) -> Field:
+ return Field(start_bit=4, width=4, name="Pointer byte bits", parser=None)
+
+
+# 8b registers used to determine the type of operation to be performed by the AD5593R when subsequent data bytes arrive
+POINTER_BYTE_MAP = RegisterDict()
+
+POINTER_BYTE_MAP[0x00] = Register(
+ opcode=0x00,
+ name="CONFIG_MODE_POINTER",
+ fields=[
+ Field(
+ start_bit=0,
+ width=4,
+ name="CONFIG_MODE_BITS",
+ parser=lambda x: CONFIG_MODE_BITS_MAP.get(x, "UNKNOWN"),
+ ),
+ Field(
+ start_bit=4,
+ width=4,
+ name="CONFIG_MODE_SEL",
+ parser=decimal_to_hex,
+ ),
+ ],
+)
+
+POINTER_BYTE_MAP[0x01] = Register(
+ opcode=0x01,
+ name="DAC_WR_POINTER",
+ fields=[
+ Field(
+ start_bit=0,
+ width=4,
+ name="DAC_CH_SEL_WR",
+ parser=DAC_chn,
+ ),
+ Field(
+ start_bit=4,
+ width=4,
+ name="DAC_WR_SEL",
+ parser=decimal_to_hex,
+ ),
+ ],
+)
+
+POINTER_BYTE_MAP[0x04] = Register(
+ opcode=0x04,
+ name="ADC_RD_POINTER",
+ fields=[
+ Field(
+ start_bit=0,
+ width=4,
+ name="RESERVED",
+ parser=empty_str,
+ ),
+ Field(
+ start_bit=4,
+ width=4,
+ name="ADC_RD_SEL",
+ parser=decimal_to_hex,
+ ),
+ ],
+)
+
+POINTER_BYTE_MAP[0x05] = Register(
+ opcode=0x05,
+ name="DAC_RD_POINTER",
+ fields=[
+ Field(
+ start_bit=0,
+ width=4,
+ name="DAC_CH_SEL_RD",
+ parser=DAC_chn,
+ ),
+ Field(
+ start_bit=4,
+ width=4,
+ name="DAC_RD_SEL",
+ parser=decimal_to_hex,
+ ),
+ ],
+)
+
+POINTER_BYTE_MAP[0x06] = Register(
+ opcode=0x06,
+ name="GPIO_RD_POINTER",
+ fields=[
+ Field(
+ start_bit=0,
+ width=4,
+ name="RESERVED",
+ parser=empty_str,
+ ),
+ Field(
+ start_bit=4,
+ width=4,
+ name="GPIO_RD_SEL",
+ parser=decimal_to_hex,
+ ),
+ ],
+)
+
+POINTER_BYTE_MAP[0x07] = Register(
+ opcode=0x07,
+ name="REG_RD_POINTER",
+ fields=[
+ Field(
+ start_bit=0,
+ width=4,
+ name="DAC_CH_SEL_WR", # Select control register for readback
+ parser=lambda x: REG_SEL_RD_MAP.get(x, "UNKNOWN"),
+ ),
+ Field(
+ start_bit=4,
+ width=4,
+ name="REG_RD_SEL",
+ parser=decimal_to_hex,
+ ),
+ ],
+)
+
+
+REGISTER_DESCRIPTOR_MAP = RegisterDict()
+
+REGISTER_DESCRIPTOR_MAP["NOOP"] = Register(
+ opcode="NOOP",
+ name="NOOP",
+ fields=[
+ Field(
+ start_bit=0,
+ width=11,
+ name="No operation",
+ parser=empty_str,
+ ),
+ Field(
+ start_bit=11,
+ width=5,
+ name="RESERVED",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["ADC_SEQ"] = Register(
+ opcode="ADC_SEQ",
+ name="ADC_SEQ",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="ADC channels",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=1,
+ name="Temperature Indicator",
+ parser=disabled_enabled,
+ ),
+ Field(
+ start_bit=9,
+ width=1,
+ name="Repeat",
+ parser=disabled_enabled,
+ ),
+ Field(
+ start_bit=10,
+ width=6,
+ name="RESERVED",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["GEN_CTRL_REG"] = Register(
+ opcode="GEN_CTRL_REG",
+ name="GEN_CTRL_REG",
+ fields=[
+ Field(
+ start_bit=0,
+ width=4,
+ name="RESERVED",
+ parser=empty_str,
+ ),
+ Field(
+ start_bit=4,
+ width=1,
+ name="DAC_RANGE",
+ parser=vref_range,
+ ),
+ Field(
+ start_bit=5,
+ width=1,
+ name="ADC_RANGE",
+ parser=vref_range,
+ ),
+ Field(
+ start_bit=6,
+ width=1,
+ name="ALL_DAC",
+ parser=disabled_enabled,
+ ),
+ Field(
+ start_bit=7,
+ width=1,
+ name="IO_LOCK",
+ parser=disabled_enabled,
+ ),
+ Field(
+ start_bit=8,
+ width=1,
+ name="ADC_BUF_EN",
+ parser=disabled_enabled,
+ ),
+ Field(
+ start_bit=9,
+ width=1,
+ name="ADC_BUF_PRECH",
+ parser=disabled_enabled,
+ ),
+ Field(
+ start_bit=10,
+ width=6,
+ name="RESERVED",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["ADC_CONFIG"] = Register(
+ opcode="ADC_CONFIG",
+ name="ADC_CONFIG",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="ADC input pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=8,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["DAC_CONFIG"] = Register(
+ opcode="DAC_CONFIG",
+ name="DAC_CONFIG",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="DAC output pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=8,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["PULLDWN_CONFIG"] = Register(
+ opcode="PULLDWN_CONFIG",
+ name="PULLDWN_CONFIG",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="Weak-pulldown output pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=8,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["LDAC_MODE"] = Register(
+ opcode="LDAC_MODE",
+ name="LDAC_MODE",
+ fields=[
+ Field(
+ start_bit=0,
+ width=2,
+ name="LDAC_MODE",
+ parser=decimal_to_hex,
+ ),
+ Field(
+ start_bit=2,
+ width=14,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["GPIO_CONFIG"] = Register(
+ opcode="GPIO_CONFIG",
+ name="GPIO_CONFIG",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="GPIO output pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=8,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["GPIO_OUTPUT"] = Register(
+ opcode="GPIO_OUTPUT",
+ name="GPIO_OUTPUT",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="GPIO high pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=8,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["GPIO_INPUT"] = Register(
+ opcode="GPIO_INPUT",
+ name="GPIO_INPUT",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="GPIO input pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=8,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["PD_REF_CTRL"] = Register(
+ opcode="PD_REF_CTRL",
+ name="PD_REF_CTRL",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="DAC power-down pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=1,
+ name="RESERVED",
+ parser=empty_str,
+ ),
+ Field(
+ start_bit=9,
+ width=1,
+ name="EN_REF",
+ parser=disabled_enabled,
+ ),
+ Field(
+ start_bit=10,
+ width=1,
+ name="PD_ALL",
+ parser=disabled_enabled,
+ ),
+ Field(
+ start_bit=11,
+ width=5,
+ name="RESERVED",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["GPIO_OPENDRAIN_CONFIG"] = Register(
+ opcode="GPIO_OPENDRAIN_CONFIG",
+ name="GPIO_OPENDRAIN_CONFIG",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="GPIO open-drain pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=8,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["IO_TS_CONFIG"] = Register(
+ opcode="IO_TS_CONFIG",
+ name="IO_TS_CONFIG",
+ fields=[
+ Field(
+ start_bit=0,
+ width=8,
+ name="Three-state output pins",
+ parser=bit_indices,
+ ),
+ Field(
+ start_bit=8,
+ width=8,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["SW_RESET"] = Register(
+ opcode="SW_RESET",
+ name="SW_RESET",
+ fields=[
+ Field(
+ start_bit=0,
+ width=11,
+ name="Reset command",
+ parser=decimal_to_hex,
+ ),
+ Field(
+ start_bit=11,
+ width=5,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["DAC_WR"] = Register(
+ opcode="DAC_WR",
+ name="DAC_WR",
+ fields=[
+ Field(start_bit=0, width=12, name="DAC data", parser=None),
+ Field(
+ start_bit=12,
+ width=4,
+ name="RESERVERD",
+ parser=empty_str,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["DAC_DATA_RD"] = Register(
+ opcode="DAC_DATA_RD",
+ name="DAC_DATA_RD",
+ fields=[
+ Field(start_bit=0, width=12, name="DAC_DATA", parser=None),
+ Field(
+ start_bit=12,
+ width=3,
+ name="DAC_ADDR",
+ parser=DAC_chn,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["ADC_RESULT"] = Register(
+ opcode="ADC_RESULT",
+ name="ADC_RESULT",
+ fields=[
+ Field(start_bit=0, width=12, name="ADC_DATA", parser=None),
+ Field(
+ start_bit=12,
+ width=3,
+ name="ADC_ADDR",
+ parser=ADC_chn,
+ ),
+ ],
+)
+
+REGISTER_DESCRIPTOR_MAP["TMP_SENSE_RESULT"] = Register(
+ opcode="TMP_SENSE_RESULT",
+ name="TMP_SENSE_RESULT",
+ fields=[
+ Field(start_bit=0, width=12, name="ADC_DATA", parser=None),
+ Field(
+ start_bit=12,
+ width=4,
+ name="TMPSENSE_ADDR",
+ parser=decimal_to_hex,
+ ),
+ ],
+)
diff --git a/decoders/ad5593r/pd.py b/decoders/ad5593r/pd.py
new file mode 100644
index 00000000..520dfe30
--- /dev/null
+++ b/decoders/ad5593r/pd.py
@@ -0,0 +1,255 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2024 Analog Devices Inc.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see .
+##
+
+import sigrokdecode as srd
+
+from common.srdhelper import SrdIntEnum, bitpack_lsb
+from .lists import (
+ POINTER_BYTE_MAP,
+ REGISTER_DESCRIPTOR_MAP,
+ Field,
+ Register,
+)
+from typing import List
+
+
+(OPERATION_WRITE, OPERATION_READ) = range(2)
+Ann = SrdIntEnum.from_str("Ann", "REGISTER FIELD POINTER_BYTE SLAVE_ADDR DATA_BYTE WARNING")
+
+
+class Decoder(srd.Decoder):
+ api_version = 3
+ id = "ad5593r"
+ name = "AD5593R"
+ longname = "Analog Devices AAD5593"
+ desc = "Analog Devices AD5593R 12-bit configurable ADC/DAC."
+ license = "gplv3+"
+ inputs = ["i2c"]
+ outputs = []
+ tags = ["IC", "Analog/digital"]
+ options = ({"id": "Vref", "desc": "Reference voltage (V)", "default": 2.5},)
+ annotations = (
+ ("register", "Register"),
+ ("field", "Field"),
+ ("ptr_byte", "Pointer Byte"),
+ ("slave_addr", "Slave Address"),
+ ("data_byte", "Data Byte"),
+ ("warning", "Warning"),
+ )
+ annotation_rows = (
+ ("packet", "Packets", (Ann.POINTER_BYTE, Ann.SLAVE_ADDR, Ann.WARNING, Ann.DATA_BYTE)),
+ ("registers", "Registers", (Ann.REGISTER,)),
+ ("fields", "Fields", (Ann.FIELD,)),
+ )
+
+ def __init__(self):
+ self.reset()
+
+ def reset(self):
+ self.state = "IDLE"
+ # Delimiter of 8b I2C block
+ self.ss = -1
+ self.es = -1
+ # I2C transaction over multiple 8b blocks
+ self.ss_block = -1
+ self.es_block = -1
+ # Internal buffer
+ self.bits = []
+ self.IO_operation_type = -1
+ # Databyte format which is determined by the pointer byte
+ self.databyte_register = ""
+
+ def start(self):
+ self.out_ann = self.register(srd.OUTPUT_ANN)
+
+ def putg(self, ss, es, ann_idx, data):
+ # Annotates a bit field of an I²C packet
+ self.put(ss, es, self.out_ann, [ann_idx, data])
+
+ def decode_field(self, bits, name, offset, width, parser=None):
+ val, (ss, es) = self.bit_slice_to_int(bits, offset, width)
+ formatted = parser(val) if parser else "{}".format(val)
+ if formatted is not None and formatted != "":
+ text = "{name}: {val}".format(name=name, val=formatted)
+ else:
+ text = "{name}".format(name=name)
+ self.putg(ss, es, Ann.FIELD, [text])
+
+ def handle_slave_addr(self, data):
+ if data not in (0b0010000, 0b0010001):
+ ann = "I²C slave is not compatible."
+ self.putg(self.ss, self.es, Ann.WARNING, [ann])
+ else:
+ ann = ["I²C Slave address", "I²C Slave"]
+ self.putg(self.ss, self.es, Ann.SLAVE_ADDR, ann)
+
+ def handle_databyte_decode_state(self, register: Register, data: List[int]):
+ # Handle state and determine how to parse the incomming data byte
+ if register.name == "CONFIG_MODE_POINTER":
+ # Only 1 match is expected in the list of fields. Then we extract the field from the list.
+ CONFIG_MODE_BIT_FIELD = [field for field in register.fields if field.name == "CONFIG_MODE_BITS"][0]
+ field_val, (_, _) = self.bit_slice_to_int(
+ data, CONFIG_MODE_BIT_FIELD.start_bit, CONFIG_MODE_BIT_FIELD.width
+ )
+ self.databyte_register = (
+ CONFIG_MODE_BIT_FIELD.parser(field_val) if CONFIG_MODE_BIT_FIELD.parser is not None else "UNKNOWN"
+ )
+ if self.databyte_register == "UNKNOWN":
+ raise ValueError("Unknown CONFIG_MODE_BITS value")
+ elif register.name == "DAC_WR_POINTER":
+ self.databyte_register = "DAC_WR"
+ elif register.name == "ADC_RD_POINTER":
+ self.databyte_register = "ADC_RESULT"
+ elif register.name == "DAC_RD_POINTER":
+ self.databyte_register = "DAC_DATA_RD"
+ elif register.name == "GPIO_RD_POINTER":
+ if self.IO_operation_type == OPERATION_WRITE:
+ self.databyte_register = "GPIO_INPUT"
+ if self.IO_operation_type == OPERATION_READ:
+ self.databyte_register = "GPIO_OUTPUT"
+ elif register.name == "REG_RD_POINTER":
+ # Only 1 match is expected in the list of fields. Then we extract the filed from the list.
+ REG_SEL_RD_FIELD = [field for field in register.fields if field.name == "CONFIG_MODE_BITS"][0]
+ field_val, (_, _) = self.bit_slice_to_int(data, REG_SEL_RD_FIELD.start_bit, REG_SEL_RD_FIELD.width)
+ self.databyte_register = (
+ REG_SEL_RD_FIELD.parser(field_val) if REG_SEL_RD_FIELD.parser is not None else "UNKNOWN"
+ )
+ if self.databyte_register == "UNKNOWN":
+ raise ValueError("Unknown CONFIG_MODE_BITS value")
+
+ def handle_pointer_byte(self, bits: List):
+ opcode_field: Field = POINTER_BYTE_MAP.get_pointer_byte_register()
+ opcode, (_, _) = self.bit_slice_to_int(bits, offset=opcode_field.start_bit, width=opcode_field.width)
+ self.putg(self.ss, self.es, Ann.POINTER_BYTE, ["Pointer Byte", "Ptr Byte"])
+ try:
+ register: Register = POINTER_BYTE_MAP[opcode]
+ self.putg(self.ss, self.es, Ann.REGISTER, [register.name])
+ # Handle annotations
+ for field in register.fields:
+ self.decode_field(bits, field.name, field.start_bit, field.width, field.parser)
+ self.handle_databyte_decode_state(register, bits)
+ except Exception as e:
+ return
+
+ def handle_data_bytes(self, bits: List[int]) -> None:
+ try:
+ register: Register = REGISTER_DESCRIPTOR_MAP[self.databyte_register]
+ self.putg(self.ss_block, self.es_block, Ann.REGISTER, [register.name])
+
+ for field in register.fields:
+ self.decode_field(bits, field.name, field.start_bit, field.width, field.parser)
+ except Exception as e:
+ return
+
+ def store_bits(self, bits: List[int]):
+ """
+ Bits are stored in the decoder's data buffer in MSB order, index 0 corresponding to the MSB.
+ This storage order facilitates extension with new 8-bit chunks.
+ For annotation, we parse from LSB (Least Significant Bit) to MSB, which involves reversing the list again.
+ """
+ copy_bits = bits.copy()
+ copy_bits.reverse()
+ self.bits.extend(copy_bits)
+
+ def bit_slice_to_int(self, bits, offset, width):
+ bits = bits[offset:][:width] # take a slice of the bits
+ ss, es = bits[-1][1], bits[0][2]
+ value = bitpack_lsb(bits, 0)
+ return (
+ value,
+ (
+ ss,
+ es,
+ ),
+ )
+
+ def process_IO_operation(self, bits):
+ # Extracted from the address slave packet.
+ LSB, _, _ = bits[0]
+ return LSB
+
+ def get_start_sample(self, bits, idx=0):
+ bit, ss, es = bits[idx]
+ return ss
+
+ def get_end_sample(self, bits, idx=-1):
+ bit, ss, es = bits[idx]
+ return es
+
+ def decode(self, ss, es, data):
+ ptype, pdata = data
+
+ # STOP resets the state machine
+ if ptype == "STOP":
+ self.state = "IDLE"
+ self.bits = []
+ return
+
+ # State machine
+ if self.state == "IDLE":
+ if ptype not in ("START"):
+ self.state = "IDLE"
+ return
+ self.state = "GET SLAVE ADDR"
+ elif self.state == "GET SLAVE ADDR":
+ if ptype == "BITS":
+ self.ss = self.get_start_sample(pdata, idx=-1)
+ self.es = self.get_end_sample(pdata, idx=1)
+ self.IO_operation_type = self.process_IO_operation(pdata)
+ if ptype in ("ADDRESS READ", "ADDRESS WRITE"):
+ self.handle_slave_addr(pdata)
+ if ptype == "ACK" and self.IO_operation_type == OPERATION_WRITE:
+ self.state = "GET POINTER BYTE"
+ if ptype == "ACK" and self.IO_operation_type == OPERATION_READ:
+ self.state = "GET DATA HIGH"
+ elif self.state == "GET POINTER BYTE":
+ if ptype == "BITS":
+ self.ss = self.get_start_sample(pdata, idx=-1)
+ self.es = self.get_end_sample(pdata, idx=0)
+ self.store_bits(pdata)
+ if ptype in ("DATA WRITE", "DATA READ"):
+ self.bits.reverse()
+ self.handle_pointer_byte(self.bits)
+ self.bits = []
+ if ptype == "ACK":
+ self.state = "GET DATA HIGH"
+ elif self.state == "GET DATA HIGH":
+ if ptype == "BITS":
+ self.ss_block = self.get_start_sample(pdata, idx=-1)
+ self.store_bits(pdata)
+ if ptype == "ACK":
+ self.state = "GET DATA LOW"
+ elif self.state == "GET DATA LOW":
+ if ptype == "BITS":
+ self.es_block = self.get_end_sample(pdata, idx=0)
+ self.putg(
+ self.ss_block,
+ self.es_block,
+ Ann.DATA_BYTE,
+ [
+ "Data Bytes",
+ ],
+ )
+ self.store_bits(pdata)
+ self.bits.reverse()
+ # Decode and clear buffer for repeated data byte packets
+ self.handle_data_bytes(self.bits)
+ self.bits = []
+ if ptype in ("ACK", "NACK"):
+ self.state = "GET DATA HIGH"