diff options
Diffstat (limited to 'mpm/python/usrp_mpm')
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/base.py | 55 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/common.py | 209 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e31x.py | 70 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e31x_periphs.py | 196 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e320.py | 70 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e320_periphs.py | 189 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/n3xx.py | 74 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py | 144 | 
9 files changed, 272 insertions, 736 deletions
| diff --git a/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt b/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt index 987bc184b..4f8520c12 100644 --- a/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt +++ b/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt @@ -11,6 +11,7 @@ set(USRP_MPM_FILES ${USRP_MPM_FILES})  set(USRP_MPM_PERIPHMGR_FILES      ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in      ${CMAKE_CURRENT_SOURCE_DIR}/base.py +    ${CMAKE_CURRENT_SOURCE_DIR}/common.py      ${CMAKE_CURRENT_SOURCE_DIR}/n3xx.py      ${CMAKE_CURRENT_SOURCE_DIR}/n3xx_periphs.py      ${CMAKE_CURRENT_SOURCE_DIR}/e320.py diff --git a/mpm/python/usrp_mpm/periph_manager/base.py b/mpm/python/usrp_mpm/periph_manager/base.py index 4ae30778a..5e5d3889e 100644 --- a/mpm/python/usrp_mpm/periph_manager/base.py +++ b/mpm/python/usrp_mpm/periph_manager/base.py @@ -176,6 +176,8 @@ class PeriphManagerBase(object):      # Device initialization (at MPM startup)      ###########################################################################      def __init__(self): +        # This gets set in the child class +        self.mboard_regs_control = None          # Note: args is a dictionary.          assert self.pids          assert self.mboard_eeprom_magic is not None @@ -513,7 +515,7 @@ class PeriphManagerBase(object):          self.log.trace("Teardown called for Peripheral Manager base.")      ########################################################################### -    # Misc device status controls and indicators +    # RFNoC and Device info      ###########################################################################      def set_device_id(self, device_id):          """ @@ -521,7 +523,8 @@ class PeriphManagerBase(object):          The device ID is used to identify the RFNoC components associated with          this motherboard.          """ -        raise NotImplementedError("set_device_id() not implemented.") +        self.log.debug("Setting device ID to `{}'".format(device_id)) +        self.mboard_regs_control.set_device_id(device_id)      def get_device_id(self):          """ @@ -529,8 +532,28 @@ class PeriphManagerBase(object):          The device ID is used to identify the RFNoC components associated with          this motherboard.          """ -        raise NotImplementedError("get_device_id() not implemented.") +        return self.mboard_regs_control.get_device_id() + +    def get_proto_ver(self): +        """ +        Return RFNoC protocol version +        """ +        proto_ver = self.mboard_regs_control.get_proto_ver() +        self.log.debug("RFNoC protocol version supported by this device is {}".format(proto_ver)) +        return proto_ver + +    def get_chdr_width(self): +        """ +        Return RFNoC CHDR width +        """ +        chdr_width = self.mboard_regs_control.get_chdr_width() +        self.log.debug("CHDR width supported by the device is {}".format(chdr_width)) +        return chdr_width + +    ########################################################################### +    # Misc device status controls and indicators +    ###########################################################################      def get_init_status(self):          """          Returns the status of the device after its initialization (that happens @@ -611,20 +634,6 @@ class PeriphManagerBase(object):          """          return [dboard.device_info for dboard in self.dboards] -    @no_claim -    def get_proto_ver(self): -        """ -        Return RFNoC protocol version -        """ -        raise NotImplementedError("get_proto_ver() not implemented.") - -    @no_claim -    def get_chdr_width(self): -        """ -        Return RFNoC CHDR width -        """ -        raise NotImplementedError("get_chdr_width() not implemented.") -      ###########################################################################      # Component updating      ########################################################################### @@ -871,7 +880,7 @@ class PeriphManagerBase(object):          """          Return the number of timekeepers          """ -        raise NotImplementedError("get_num_timekeepers() not implemented.") +        return self.mboard_regs_control.get_num_timekeepers()      def get_timekeeper_time(self, tk_idx, last_pps):          """ @@ -881,8 +890,7 @@ class PeriphManagerBase(object):          tk_idx: Index of timekeeper          next_pps: If True, get time at last PPS. Otherwise, get time now.          """ -        raise NotImplementedError( -            "get_ticks_now({}, {}) not implemented.".format(tk_idx, last_pps)) +        return self.mboard_regs_control.get_timekeeper_time(tk_idx, last_pps)      def set_timekeeper_time(self, tk_idx, ticks, next_pps):          """ @@ -893,9 +901,7 @@ class PeriphManagerBase(object):          ticks: Time in ticks          next_pps: If True, set time at next PPS. Otherwise, set time now.          """ -        raise NotImplementedError( -            "set_ticks_last_pps({}, {}, {}) not implemented." -            .format(tk_idx, ticks, next_pps)) +        self.mboard_regs_control.set_timekeeper_time(tk_idx, ticks, next_pps)      def set_tick_period(self, tk_idx, period_ns):          """ @@ -905,8 +911,7 @@ class PeriphManagerBase(object):          tk_idx: Index of timekeeper          period_ns: Period in nanoseconds          """ -        raise NotImplementedError( -            "set_tick_period({}) not implemented.".format(tk_idx, period_ns)) +        self.mboard_regs_control.set_tick_period(tk_idx, period_ns)      def get_clocks(self):          """ diff --git a/mpm/python/usrp_mpm/periph_manager/common.py b/mpm/python/usrp_mpm/periph_manager/common.py new file mode 100644 index 000000000..e09be835e --- /dev/null +++ b/mpm/python/usrp_mpm/periph_manager/common.py @@ -0,0 +1,209 @@ +# +# Copyright 2019 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" +Common code for all MPM devices +""" + +import datetime +from usrp_mpm.sys_utils.uio import UIO + +class MboardRegsCommon(object): +    """ +    Parent class for mboard regs that are common between *all* MPM devices +    """ +    # pylint: disable=bad-whitespace +    # Global Registers +    MB_COMPAT_NUM          = 0x0000 +    MB_DATESTAMP           = 0x0004 +    MB_GIT_HASH            = 0x0008 +    MB_SCRATCH             = 0x000C +    MB_DEVICE_ID           = 0x0010 +    MB_RFNOC_INFO          = 0x0014 +    MB_NUM_TIMEKEEPERS     = 0x0048 +    # Timekeeper registers +    MB_TIME_NOW_LO         = 0x1000 +    MB_TIME_NOW_HI         = 0x1004 +    MB_TIME_EVENT_LO       = 0x1008 +    MB_TIME_EVENT_HI       = 0x100C +    MB_TIME_CTRL           = 0x1010 +    MB_TIME_LAST_PPS_LO    = 0x1014 +    MB_TIME_LAST_PPS_HI    = 0x1018 +    MB_TIME_BASE_PERIOD_LO = 0x101C +    MB_TIME_BASE_PERIOD_HI = 0x1020 +    MB_TIMEKEEPER_OFFSET   = 12 +    # Bitfield locations for the MB_RFNOC_INFO register. +    MB_RFNOC_INFO_PROTO_VER  = 0 +    MB_RFNOC_INFO_CHDR_WIDTH = 16 +    # pylint: enable=bad-whitespace + +    def __init__(self, label, log): +        self.log = log.getChild('MBRegs') +        self.regs = UIO( +            label=label, +            read_only=False +        ) +        self.poke32 = self.regs.poke32 +        self.peek32 = self.regs.peek32 + +    ########################################################################### +    # Device ID +    ########################################################################### +    def set_device_id(self, device_id): +        """ +        Set device ID +        """ +        with self.regs: +            self.log.trace("Writing MB_DEVICE_ID with 0x{:08X}".format(device_id)) +            return self.poke32(self.MB_DEVICE_ID, device_id) + +    def get_device_id(self): +        """ +        Get device ID +        """ +        with self.regs: +            regs_val = self.peek32(self.MB_DEVICE_ID) +            device_id = regs_val & 0x0000ffff +            self.log.trace("Read MB_DEVICE_ID 0x{:08X}".format(device_id)) +            return device_id + +    ########################################################################### +    # FPGA Identification +    ########################################################################### +    def get_compat_number(self): +        """get FPGA compat number + +        This function reads back FPGA compat number. +        The return is a tuple of 2 numbers: +        (major compat number, minor compat number) +        """ +        with self.regs: +            compat_number = self.peek32(self.MB_COMPAT_NUM) +        minor = compat_number & 0xff +        major = (compat_number>>16) & 0xff +        return (major, minor) + +    def get_build_timestamp(self): +        """ +        Returns the build date/time for the FPGA image. +        The return value is a datetime string in ISO 8601 format +        (YYYY-MM-DD HH:MM:SS.mmmmmm) +        """ +        with self.regs: +            datestamp_rb = self.peek32(self.MB_DATESTAMP) +        if datestamp_rb > 0: +            dt_str = datetime.datetime( +                year=((datestamp_rb>>17)&0x3F)+2000, +                month=(datestamp_rb>>23)&0x0F, +                day=(datestamp_rb>>27)&0x1F, +                hour=(datestamp_rb>>12)&0x1F, +                minute=(datestamp_rb>>6)&0x3F, +                second=((datestamp_rb>>0)&0x3F)) +            self.log.trace("FPGA build timestamp: {}".format(str(dt_str))) +            return str(dt_str) +        # Compatibility with FPGAs without datestamp capability +        return '' + +    def get_git_hash(self): +        """ +        Returns the GIT hash for the FPGA build. +        The return is a tuple of 2 numbers: +        (short git hash, string: dirty/clean) +        """ +        with self.regs: +            git_hash_rb = self.peek32(self.MB_GIT_HASH) +        git_hash = git_hash_rb & 0x0FFFFFFF +        tree_dirty = ((git_hash_rb & 0xF0000000) > 0) +        dirtiness_qualifier = 'dirty' if tree_dirty else 'clean' +        self.log.trace("FPGA build GIT Hash: {:07x} ({})".format( +            git_hash, dirtiness_qualifier)) +        return (git_hash, dirtiness_qualifier) + +    def get_proto_ver(self): +        """ +        Return RFNoC protocol version +        """ +        with self.regs: +            reg_val = self.peek32(self.MB_RFNOC_INFO) +            proto_ver = (reg_val & 0x0000ffff) >> self.MB_RFNOC_INFO_PROTO_VER +            self.log.trace("Read RFNOC_PROTO_VER 0x{:08X}".format(proto_ver)) +            return proto_ver + +    def get_chdr_width(self): +        """ +        Return RFNoC CHDR width +        """ +        with self.regs: +            reg_val = self.peek32(self.MB_RFNOC_INFO) +            chdr_width = (reg_val & 0xffff0000) >> self.MB_RFNOC_INFO_CHDR_WIDTH +            self.log.trace("Read RFNOC_CHDR_WIDTH 0x{:08X}".format(chdr_width)) +            return chdr_width + +    ########################################################################### +    # Timekeeper API +    ########################################################################### +    def get_num_timekeepers(self): +        """ +        Return the number of timekeepers +        """ +        with self.regs: +            return self.peek32(self.MB_NUM_TIMEKEEPERS) + +    def get_timekeeper_time(self, tk_idx, last_pps): +        """ +        Get the time in ticks + +        Arguments: +        tk_idx: Index of timekeeper +        next_pps: If True, get time at last PPS. Otherwise, get time now. +        """ +        addr_lo = \ +            (self.MB_TIME_LAST_PPS_LO if last_pps else self.MB_TIME_NOW_LO) + \ +            tk_idx * self.MB_TIMEKEEPER_OFFSET +        addr_hi = addr_lo + 4 +        with self.regs: +            time_lo = self.peek32(addr_lo) +            time_hi = self.peek32(addr_hi) +        return (time_hi << 32) | time_lo + +    def set_timekeeper_time(self, tk_idx, ticks, next_pps): +        """ +        Set the time in ticks + +        Arguments: +        tk_idx: Index of timekeeper +        ticks: Time in ticks +        next_pps: If True, set time at next PPS. Otherwise, set time now. +        """ +        addr_lo = \ +            self.MB_TIME_EVENT_LO + tk_idx * self.MB_TIMEKEEPER_OFFSET +        addr_hi = addr_lo + 4 +        addr_ctrl = \ +            self.MB_TIME_CTRL + tk_idx * self.MB_TIMEKEEPER_OFFSET +        time_lo = ticks & 0xFFFFFFFF +        time_hi = (ticks >> 32) & 0xFFFFFFFF +        time_ctrl = 0x2 if next_pps else 0x1 +        self.log.trace("Setting time on timekeeper %d to %d %s", tk_idx, ticks, +                       ("on next pps" if next_pps else "now")) +        with self.regs: +            self.poke32(addr_lo, time_lo) +            self.poke32(addr_hi, time_hi) +            self.poke32(addr_ctrl, time_ctrl) + +    def set_tick_period(self, tk_idx, period_ns): +        """ +        Set the time per tick in nanoseconds (tick period) + +        Arguments: +        tk_idx: Index of timekeeper +        period_ns: Period in nanoseconds +        """ +        addr_lo = self.MB_TIME_BASE_PERIOD_LO + tk_idx * self.MB_TIMEKEEPER_OFFSET +        addr_hi = addr_lo + 4 +        period_lo = period_ns & 0xFFFFFFFF +        period_hi = (period_ns >> 32) & 0xFFFFFFFF +        with self.regs: +            self.poke32(addr_lo, period_lo) +            self.poke32(addr_hi, period_hi) diff --git a/mpm/python/usrp_mpm/periph_manager/e31x.py b/mpm/python/usrp_mpm/periph_manager/e31x.py index 573e75d55..8ba8ff034 100644 --- a/mpm/python/usrp_mpm/periph_manager/e31x.py +++ b/mpm/python/usrp_mpm/periph_manager/e31x.py @@ -509,39 +509,6 @@ class e31x(ZynqComponents, PeriphManagerBase):          })          return device_info -    def set_device_id(self, device_id): -        """ -        Sets the device ID for this motherboard. -        The device ID is used to identify the RFNoC components associated with -        this motherboard. -        """ -        self.log.debug("Setting device ID to `{}'".format(device_id)) -        self.mboard_regs_control.set_device_id(device_id) - -    def get_device_id(self): -        """ -        Gets the device ID for this motherboard. -        The device ID is used to identify the RFNoC components associated with -        this motherboard. -        """ -        return self.mboard_regs_control.get_device_id() - -    def get_proto_ver(self): -        """ -        Return RFNoC protocol version -        """ -        proto_ver = self.mboard_regs_control.get_proto_ver() -        self.log.debug("RFNoC protocol version supported by this device is {}".format(proto_ver)) -        return proto_ver - -    def get_chdr_width(self): -        """ -        Return RFNoC CHDR width -        """ -        chdr_width = self.mboard_regs_control.get_chdr_width() -        self.log.debug("CHDR width supported by the device is {}".format(chdr_width)) -        return chdr_width -      ###########################################################################      # Clock/Time API      ########################################################################### @@ -738,43 +705,6 @@ class e31x(ZynqComponents, PeriphManagerBase):      #######################################################################      # Timekeeper API      ####################################################################### -    def get_num_timekeepers(self): -        """ -        Return the number of timekeepers -        """ -        return self.mboard_regs_control.get_num_timekeepers() - -    def get_timekeeper_time(self, tk_idx, last_pps): -        """ -        Get the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        next_pps: If True, get time at last PPS. Otherwise, get time now. -        """ -        return self.mboard_regs_control.get_timekeeper_time(tk_idx, last_pps) - -    def set_timekeeper_time(self, tk_idx, ticks, next_pps): -        """ -        Set the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        ticks: Time in ticks -        next_pps: If True, set time at next PPS. Otherwise, set time now. -        """ -        self.mboard_regs_control.set_timekeeper_time(tk_idx, ticks, next_pps) - -    def set_tick_period(self, tk_idx, period_ns): -        """ -        Set the time per tick in nanoseconds (tick period) - -        Arguments: -        tk_idx: Index of timekeeper -        period_ns: Period in nanoseconds -        """ -        self.mboard_regs_control.set_tick_period(tk_idx, period_ns) -      def get_clocks(self):          """          Gets the RFNoC-related clocks present in the FPGA design diff --git a/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py b/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py index 330cd830e..84c60d2ce 100644 --- a/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py +++ b/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py @@ -1,5 +1,6 @@  #  # Copyright 2018 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Brand  #  # SPDX-License-Identifier: GPL-3.0-or-later  # @@ -7,11 +8,10 @@  E310 peripherals  """ -import datetime -import math  from usrp_mpm.sys_utils.sysfs_gpio import SysFSGPIO, GPIOBank -from usrp_mpm.sys_utils.uio import UIO +from usrp_mpm.periph_manager.common import MboardRegsCommon +# pylint: disable=too-few-public-methods  class FrontpanelGPIO(GPIOBank):      """      Abstraction layer for the front panel GPIO @@ -27,18 +27,14 @@ class FrontpanelGPIO(GPIOBank):              0xFF, # use_mask              ddr          ) +# pylint: enable=too-few-public-methods -class MboardRegsControl(object): +class MboardRegsControl(MboardRegsCommon):      """      Control the FPGA Motherboard registers      """ +    # pylint: disable=bad-whitespace      # Motherboard registers -    MB_COMPAT_NUM       = 0x0000 -    MB_DATESTAMP        = 0x0004 -    MB_GIT_HASH         = 0x0008 -    MB_SCRATCH          = 0x000C -    MB_DEVICE_ID        = 0x0010 -    MB_RFNOC_INFO       = 0x0014      MB_CLOCK_CTRL       = 0x0018      MB_XADC_RB          = 0x001C      MB_BUS_CLK_RATE     = 0x0020 @@ -51,26 +47,12 @@ class MboardRegsControl(object):      MB_GPS_STATUS       = 0x003C      MB_DBOARD_CTRL      = 0x0040      MB_DBOARD_STATUS    = 0x0044 -    MB_NUM_TIMEKEEPERS  = 0x0048 -    # Timekeeper registers -    MB_TIME_NOW_LO         = 0x1000 -    MB_TIME_NOW_HI         = 0x1004 -    MB_TIME_EVENT_LO       = 0x1008 -    MB_TIME_EVENT_HI       = 0x100C -    MB_TIME_CTRL           = 0x1010 -    MB_TIME_LAST_PPS_LO    = 0x1014 -    MB_TIME_LAST_PPS_HI    = 0x1018 -    MB_TIME_BASE_PERIOD_LO = 0x101C -    MB_TIME_BASE_PERIOD_HI = 0x1020 -    MB_TIMEKEEPER_OFFSET   = 12 - -    # Bitfield locations for the MB_RFNOC_INFO register. -    MB_RFNOC_INFO_PROTO_VER = 0 -    MB_RFNOC_INFO_CHDR_WIDTH = 16      # Bitfield locations for the MB_CLOCK_CTRL register.      MB_CLOCK_CTRL_PPS_SEL_INT = 0      MB_CLOCK_CTRL_PPS_SEL_EXT = 1 +    # FIXME: This value is probably wrong +    MB_CLOCK_CTRL_PPS_SEL_GPS = 2      MB_CLOCK_CTRL_REF_CLK_LOCKED = 2      # Bitfield locations for the MB_GPS_CTRL register. @@ -94,48 +76,10 @@ class MboardRegsControl(object):      # Bitfield locations for the MB_DBOARD_STATUS register.      MB_DBOARD_STATUS_RX_LOCK = 6      MB_DBOARD_STATUS_TX_LOCK = 7 +    # pylint: enable=bad-whitespace      def __init__(self, label, log): -        self.log = log -        self.regs = UIO( -            label=label, -            read_only=False -        ) -        self.poke32 = self.regs.poke32 -        self.peek32 = self.regs.peek32 - -    def get_compat_number(self): -        """get FPGA compat number - -        This function reads back FPGA compat number. -        The return is a tuple of -        2 numbers: (major compat number, minor compat number ) -        """ -        with self.regs: -            compat_number = self.peek32(self.MB_COMPAT_NUM) -        minor = compat_number & 0xff -        major = (compat_number>>16) & 0xff -        return (major, minor) - -    def get_proto_ver(self): -        """ -        Return RFNoC protocol version -        """ -        with self.regs: -            reg_val = self.peek32(self.MB_RFNOC_INFO) -            proto_ver = (reg_val & 0x0000ffff) >> self.MB_RFNOC_INFO_PROTO_VER -            self.log.trace("Read RFNOC_PROTO_VER 0x{:08X}".format(proto_ver)) -            return proto_ver - -    def get_chdr_width(self): -        """ -        Return RFNoC CHDR width -        """ -        with self.regs: -            reg_val = self.peek32(self.MB_RFNOC_INFO) -            chdr_width = (reg_val & 0xffff0000) >> self.MB_RFNOC_INFO_CHDR_WIDTH -            self.log.trace("Read RFNOC_CHDR_WIDTH 0x{:08X}".format(chdr_width)) -            return chdr_width +        MboardRegsCommon.__init__(self, label, log)      def set_fp_gpio_master(self, value):          """set driver for front panel GPIO @@ -173,61 +117,6 @@ class MboardRegsControl(object):          with self.regs:              return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xffffff -    def set_device_id(self, device_id): -        """ -        Set device ID -        """ -        with self.regs: -            self.log.trace("Writing MB_DEVICE_ID with 0x{:08X}".format(device_id)) -            return self.poke32(self.MB_DEVICE_ID, device_id) - -    def get_device_id(self): -        """ -        Get device ID -        """ -        with self.regs: -            regs_val = self.peek32(self.MB_DEVICE_ID) -            device_id = regs_val & 0x0000ffff -            self.log.trace("Read MB_DEVICE_ID 0x{:08X}".format(device_id)) -            return device_id - -    def get_build_timestamp(self): -        """ -        Returns the build date/time for the FPGA image. -        The return is datetime string with the  ISO 8601 format -        (YYYY-MM-DD HH:MM:SS.mmmmmm) -        """ -        with self.regs: -            datestamp_rb = self.peek32(self.MB_DATESTAMP) -        if datestamp_rb > 0: -            dt_str = datetime.datetime( -                year=((datestamp_rb>>17)&0x3F)+2000, -                month=(datestamp_rb>>23)&0x0F, -                day=(datestamp_rb>>27)&0x1F, -                hour=(datestamp_rb>>12)&0x1F, -                minute=(datestamp_rb>>6)&0x3F, -                second=((datestamp_rb>>0)&0x3F)) -            self.log.trace("FPGA build timestamp: {}".format(str(dt_str))) -            return str(dt_str) -        else: -            # Compatibility with FPGAs without datestamp capability -            return '' - -    def get_git_hash(self): -        """ -        Returns the GIT hash for the FPGA build. -        The return is a tuple of -        2 numbers: (short git hash, bool: is the tree dirty?) -        """ -        with self.regs: -            git_hash_rb = self.peek32(self.MB_GIT_HASH) -        git_hash = git_hash_rb & 0x0FFFFFFF -        tree_dirty = ((git_hash_rb & 0xF0000000) > 0) -        dirtiness_qualifier = 'dirty' if tree_dirty else 'clean' -        self.log.trace("FPGA build GIT Hash: {:07x} ({})".format( -            git_hash, dirtiness_qualifier)) -        return (git_hash, dirtiness_qualifier) -      def set_time_source(self, time_source):          """          Set time source @@ -261,71 +150,6 @@ class MboardRegsControl(object):          else:              assert False, "Cannot set to invalid clock source: {}".format(clock_source) -    def get_num_timekeepers(self): -        """ -        Return the number of timekeepers -        """ -        with self.regs: -            return self.peek32(self.MB_NUM_TIMEKEEPERS) - -    def get_timekeeper_time(self, tk_idx, last_pps): -        """ -        Get the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        next_pps: If True, get time at last PPS. Otherwise, get time now. -        """ -        addr_lo = \ -            (self.MB_TIME_LAST_PPS_LO if last_pps else self.MB_TIME_NOW_LO) + \ -            tk_idx * self.MB_TIMEKEEPER_OFFSET -        addr_hi = addr_lo + 4 -        with self.regs: -            time_lo = self.peek32(addr_lo) -            time_hi = self.peek32(addr_hi) -        return time_hi << 32 | time_lo - - -    def set_timekeeper_time(self, tk_idx, ticks, next_pps): -        """ -        Set the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        ticks: Time in ticks -        next_pps: If True, set time at next PPS. Otherwise, set time now. -        """ -        addr_lo = \ -            self.MB_TIME_EVENT_LO + tk_idx * self.MB_TIMEKEEPER_OFFSET -        addr_hi = addr_lo + 4 -        addr_ctrl = \ -            self.MB_TIME_CTRL + tk_idx * self.MB_TIMEKEEPER_OFFSET -        time_lo = ticks & 0xFFFFFFFF -        time_hi = (ticks > 32) & 0xFFFFFFFF -        time_ctrl = 0x2 if next_pps else 0x1 -        self.log.trace("Setting time on timekeeper %d to %d %s", tk_idx, ticks, -                       ("on next pps" if next_pps else "now")) -        with self.regs: -            self.poke32(addr_lo, time_lo) -            self.poke32(addr_hi, time_hi) -            self.poke32(addr_ctrl, time_ctrl) - -    def set_tick_period(self, tk_idx, period_ns): -        """ -        Set the time per tick in nanoseconds (tick period) - -        Arguments: -        tk_idx: Index of timekeeper -        period_ns: Period in nanoseconds -        """ -        addr_lo = self.MB_TIME_BASE_PERIOD_LO + tk_idx * self.MB_TIMEKEEPER_OFFSET -        addr_hi = addr_lo + 4 -        period_lo = period_ns & 0xFFFFFFFF -        period_hi = (period_ns > 32) & 0xFFFFFFFF -        with self.regs: -            self.poke32(addr_lo, period_lo) -            self.poke32(addr_hi, period_hi) -      def get_fpga_type(self):          """          Reads the type of the FPGA image currently loaded diff --git a/mpm/python/usrp_mpm/periph_manager/e320.py b/mpm/python/usrp_mpm/periph_manager/e320.py index d48f90cbd..90cc1c049 100644 --- a/mpm/python/usrp_mpm/periph_manager/e320.py +++ b/mpm/python/usrp_mpm/periph_manager/e320.py @@ -410,39 +410,6 @@ class e320(ZynqComponents, PeriphManagerBase):          })          return device_info -    def set_device_id(self, device_id): -        """ -        Sets the device ID for this motherboard. -        The device ID is used to identify the RFNoC components associated with -        this motherboard. -        """ -        self.log.debug("Setting device ID to `{}'".format(device_id)) -        self.mboard_regs_control.set_device_id(device_id) - -    def get_device_id(self): -        """ -        Gets the device ID for this motherboard. -        The device ID is used to identify the RFNoC components associated with -        this motherboard. -        """ -        return self.mboard_regs_control.get_device_id() - -    def get_proto_ver(self): -        """ -        Return RFNoC protocol version -        """ -        proto_ver = self.mboard_regs_control.get_proto_ver() -        self.log.debug("RFNoC protocol version supported by this device is {}".format(proto_ver)) -        return proto_ver - -    def get_chdr_width(self): -        """ -        Return RFNoC CHDR width -        """ -        chdr_width = self.mboard_regs_control.get_chdr_width() -        self.log.debug("CHDR width supported by the device is {}".format(chdr_width)) -        return chdr_width -      ###########################################################################      # Clock/Time API      ########################################################################### @@ -753,43 +720,6 @@ class e320(ZynqComponents, PeriphManagerBase):      #######################################################################      # Timekeeper API      ####################################################################### -    def get_num_timekeepers(self): -        """ -        Return the number of timekeepers -        """ -        return self.mboard_regs_control.get_num_timekeepers() - -    def get_timekeeper_time(self, tk_idx, last_pps): -        """ -        Get the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        next_pps: If True, get time at last PPS. Otherwise, get time now. -        """ -        return self.mboard_regs_control.get_timekeeper_time(tk_idx, last_pps) - -    def set_timekeeper_time(self, tk_idx, ticks, next_pps): -        """ -        Set the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        ticks: Time in ticks -        next_pps: If True, set time at next PPS. Otherwise, set time now. -        """ -        self.mboard_regs_control.set_timekeeper_time(tk_idx, ticks, next_pps) - -    def set_tick_period(self, tk_idx, period_ns): -        """ -        Set the time per tick in nanoseconds (tick period) - -        Arguments: -        tk_idx: Index of timekeeper -        period_ns: Period in nanoseconds -        """ -        self.mboard_regs_control.set_tick_period(tk_idx, period_ns) -      def get_clocks(self):          """          Gets the RFNoC-related clocks present in the FPGA design diff --git a/mpm/python/usrp_mpm/periph_manager/e320_periphs.py b/mpm/python/usrp_mpm/periph_manager/e320_periphs.py index cad5c39ad..8dcd5a9ba 100644 --- a/mpm/python/usrp_mpm/periph_manager/e320_periphs.py +++ b/mpm/python/usrp_mpm/periph_manager/e320_periphs.py @@ -7,10 +7,9 @@  E320 peripherals  """ -import datetime  import math  from usrp_mpm.sys_utils.sysfs_gpio import SysFSGPIO, GPIOBank -from usrp_mpm.sys_utils.uio import UIO +from usrp_mpm.periph_manager.common import MboardRegsCommon  # Map register values to SFP transport types  E320_SFP_TYPES = { @@ -43,17 +42,12 @@ class FrontpanelGPIO(GPIOBank):              ddr          ) -class MboardRegsControl(object): +class MboardRegsControl(MboardRegsCommon):      """      Control the FPGA Motherboard registers      """ +    # pylint: disable=bad-whitespace      # Motherboard registers -    MB_COMPAT_NUM      = 0x0000 -    MB_DATESTAMP       = 0x0004 -    MB_GIT_HASH        = 0x0008 -    MB_SCRATCH         = 0x000C -    MB_DEVICE_ID       = 0x0010 -    MB_RFNOC_INFO      = 0x0014      MB_CLOCK_CTRL      = 0x0018      MB_XADC_RB         = 0x001C      MB_BUS_CLK_RATE    = 0x0020 @@ -66,22 +60,7 @@ class MboardRegsControl(object):      MB_GPS_STATUS      = 0x003C      MB_DBOARD_CTRL     = 0x0040      MB_DBOARD_STATUS   = 0x0044 -    MB_NUM_TIMEKEEPERS = 0x0048 -    # Timekeeper registers -    MB_TIME_NOW_LO         = 0x1000 -    MB_TIME_NOW_HI         = 0x1004 -    MB_TIME_EVENT_LO       = 0x1008 -    MB_TIME_EVENT_HI       = 0x100C -    MB_TIME_CTRL           = 0x1010 -    MB_TIME_LAST_PPS_LO    = 0x1014 -    MB_TIME_LAST_PPS_HI    = 0x1018 -    MB_TIME_BASE_PERIOD_LO = 0x101C -    MB_TIME_BASE_PERIOD_HI = 0x1020 -    MB_TIMEKEEPER_OFFSET   = 12 - -    # Bitfield locations for the MB_RFNOC_INFO register. -    MB_RFNOC_INFO_PROTO_VER = 0 -    MB_RFNOC_INFO_CHDR_WIDTH = 16 +    # pylint: enable=bad-whitespace      # Bitfield locations for the MB_CLOCK_CTRL register.      MB_CLOCK_CTRL_PPS_SEL_INT = 0 @@ -116,64 +95,7 @@ class MboardRegsControl(object):      MB_DBOARD_STATUS_TX_LOCK = 7      def __init__(self, label, log): -        self.log = log -        self.regs = UIO( -            label=label, -            read_only=False -        ) -        self.poke32 = self.regs.poke32 -        self.peek32 = self.regs.peek32 - -    def get_compat_number(self): -        """get FPGA compat number - -        This function reads back FPGA compat number. -        The return is a tuple of -        2 numbers: (major compat number, minor compat number ) -        """ -        with self.regs: -            compat_number = self.peek32(self.MB_COMPAT_NUM) -        minor = compat_number & 0xff -        major = (compat_number>>16) & 0xff -        return (major, minor) - -    def set_device_id(self, device_id): -        """ -        Set device ID -        """ -        with self.regs: -            self.log.trace("Writing MB_DEVICE_ID with 0x{:08X}".format(device_id)) -            return self.poke32(self.MB_DEVICE_ID, device_id) - -    def get_device_id(self): -        """ -        Get device ID -        """ -        with self.regs: -            reg_val = self.peek32(self.MB_DEVICE_ID) -            device_id = reg_val & 0x0000ffff -            self.log.trace("Read MB_DEVICE_ID 0x{:08X}".format(device_id)) -            return device_id - -    def get_proto_ver(self): -        """ -        Return RFNoC protocol version -        """ -        with self.regs: -            reg_val = self.peek32(self.MB_RFNOC_INFO) -            proto_ver = (reg_val & 0x0000ffff) >> self.MB_RFNOC_INFO_PROTO_VER -            self.log.trace("Read RFNOC_PROTO_VER 0x{:08X}".format(proto_ver)) -            return proto_ver; - -    def get_chdr_width(self): -        """ -        Return RFNoC CHDR width -        """ -        with self.regs: -            reg_val = self.peek32(self.MB_RFNOC_INFO) -            chdr_width = (reg_val & 0xffff0000) >> self.MB_RFNOC_INFO_CHDR_WIDTH -            self.log.trace("Read RFNOC_CHDR_WIDTH 0x{:08X}".format(chdr_width)) -            return chdr_width +        MboardRegsCommon.__init__(self, label, log)      def enable_fp_gpio(self, enable):          """ Enable front panel GPIO buffers and power supply @@ -261,43 +183,6 @@ class MboardRegsControl(object):          with self.regs:              return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xffffff -    def get_build_timestamp(self): -        """ -        Returns the build date/time for the FPGA image. -        The return is datetime string with the  ISO 8601 format -        (YYYY-MM-DD HH:MM:SS.mmmmmm) -        """ -        with self.regs: -            datestamp_rb = self.peek32(self.MB_DATESTAMP) -        if datestamp_rb > 0: -            dt_str = datetime.datetime( -                year=((datestamp_rb>>17)&0x3F)+2000, -                month=(datestamp_rb>>23)&0x0F, -                day=(datestamp_rb>>27)&0x1F, -                hour=(datestamp_rb>>12)&0x1F, -                minute=(datestamp_rb>>6)&0x3F, -                second=((datestamp_rb>>0)&0x3F)) -            self.log.trace("FPGA build timestamp: {}".format(str(dt_str))) -            return str(dt_str) -        else: -            # Compatibility with FPGAs without datestamp capability -            return '' - -    def get_git_hash(self): -        """ -        Returns the GIT hash for the FPGA build. -        The return is a tuple of -        2 numbers: (short git hash, bool: is the tree dirty?) -        """ -        with self.regs: -            git_hash_rb = self.peek32(self.MB_GIT_HASH) -        git_hash = git_hash_rb & 0x0FFFFFFF -        tree_dirty = ((git_hash_rb & 0xF0000000) > 0) -        dirtiness_qualifier = 'dirty' if tree_dirty else 'clean' -        self.log.trace("FPGA build GIT Hash: {:07x} ({})".format( -            git_hash, dirtiness_qualifier)) -        return (git_hash, dirtiness_qualifier) -      def set_time_source(self, time_source, ref_clk_freq):          """          Set time source @@ -469,67 +354,3 @@ class MboardRegsControl(object):              self.log.trace("RX RF PLL locked")          return locked -    def get_num_timekeepers(self): -        """ -        Return the number of timekeepers -        """ -        with self.regs: -            return self.peek32(self.MB_NUM_TIMEKEEPERS) - -    def get_timekeeper_time(self, tk_idx, last_pps): -        """ -        Get the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        next_pps: If True, get time at last PPS. Otherwise, get time now. -        """ -        addr_lo = \ -            (self.MB_TIME_LAST_PPS_LO if last_pps else self.MB_TIME_NOW_LO) + \ -            tk_idx * self.MB_TIMEKEEPER_OFFSET -        addr_hi = addr_lo + 4 -        with self.regs: -            time_lo = self.peek32(addr_lo) -            time_hi = self.peek32(addr_hi) -        return time_hi << 32 | time_lo - - -    def set_timekeeper_time(self, tk_idx, ticks, next_pps): -        """ -        Set the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        ticks: Time in ticks -        next_pps: If True, set time at next PPS. Otherwise, set time now. -        """ -        addr_lo = \ -            self.MB_TIME_EVENT_LO + tk_idx * self.MB_TIMEKEEPER_OFFSET -        addr_hi = addr_lo + 4 -        addr_ctrl = \ -            self.MB_TIME_CTRL + tk_idx * self.MB_TIMEKEEPER_OFFSET -        time_lo = ticks & 0xFFFFFFFF -        time_hi = (ticks > 32) & 0xFFFFFFFF -        time_ctrl = 0x2 if next_pps else 0x1 -        self.log.trace("Setting time on timekeeper %d to %d %s", tk_idx, ticks, -                       ("on next pps" if next_pps else "now")) -        with self.regs: -            self.poke32(addr_lo, time_lo) -            self.poke32(addr_hi, time_hi) -            self.poke32(addr_ctrl, time_ctrl) - -    def set_tick_period(self, tk_idx, period_ns): -        """ -        Set the time per tick in nanoseconds (tick period) - -        Arguments: -        tk_idx: Index of timekeeper -        period_ns: Period in nanoseconds -        """ -        addr_lo = self.MB_TIME_BASE_PERIOD_LO + tk_idx * self.MB_TIMEKEEPER_OFFSET -        addr_hi = addr_lo + 4 -        period_lo = period_ns & 0xFFFFFFFF -        period_hi = (period_ns > 32) & 0xFFFFFFFF -        with self.regs: -            self.poke32(addr_lo, period_lo) -            self.poke32(addr_hi, period_hi) diff --git a/mpm/python/usrp_mpm/periph_manager/n3xx.py b/mpm/python/usrp_mpm/periph_manager/n3xx.py index 5510b846d..fc9a91e7d 100644 --- a/mpm/python/usrp_mpm/periph_manager/n3xx.py +++ b/mpm/python/usrp_mpm/periph_manager/n3xx.py @@ -43,6 +43,7 @@ N32X_DEFAULT_QSFP_DRIVER_PRESET = 'Optical'  N32X_QSFP_I2C_LABEL = 'qsfp-i2c'  N3XX_FPGA_COMPAT = (7, 0)  N3XX_MONITOR_THREAD_INTERVAL = 1.0 # seconds +N3XX_BUS_CLK = 200e6  # Import daughterboard PIDs from their respective classes  MG_PID = Magnesium.pids[0] @@ -525,39 +526,6 @@ class n3xx(ZynqComponents, PeriphManagerBase):          })          return device_info -    def set_device_id(self, device_id): -        """ -        Sets the device ID for this motherboard. -        The device ID is used to identify the RFNoC components associated with -        this motherboard. -        """ -        self.log.debug("Setting device ID to `{}'".format(device_id)) -        self.mboard_regs_control.set_device_id(device_id) - -    def get_device_id(self): -        """ -        Gets the device ID for this motherboard. -        The device ID is used to identify the RFNoC components associated with -        this motherboard. -        """ -        return self.mboard_regs_control.get_device_id() - -    def get_proto_ver(self): -        """ -        Return RFNoC protocol version -        """ -        proto_ver = self.mboard_regs_control.get_proto_ver() -        self.log.debug("RFNoC protocol version supported by this device is {}".format(proto_ver)) -        return proto_ver - -    def get_chdr_width(self): -        """ -        Return RFNoC CHDR width -        """ -        chdr_width = self.mboard_regs_control.get_chdr_width() -        self.log.debug("CHDR width supported by the device is {}".format(chdr_width)) -        return chdr_width -      ###########################################################################      # Clock/Time API      ########################################################################### @@ -1051,43 +1019,6 @@ class n3xx(ZynqComponents, PeriphManagerBase):      #######################################################################      # Timekeeper API      ####################################################################### -    def get_num_timekeepers(self): -        """ -        Return the number of timekeepers -        """ -        return self.mboard_regs_control.get_num_timekeepers() - -    def get_timekeeper_time(self, tk_idx, last_pps): -        """ -        Get the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        next_pps: If True, get time at last PPS. Otherwise, get time now. -        """ -        return self.mboard_regs_control.get_timekeeper_time(tk_idx, last_pps) - -    def set_timekeeper_time(self, tk_idx, ticks, next_pps): -        """ -        Set the time in ticks - -        Arguments: -        tk_idx: Index of timekeeper -        ticks: Time in ticks -        next_pps: If True, set time at next PPS. Otherwise, set time now. -        """ -        self.mboard_regs_control.set_timekeeper_time(tk_idx, ticks, next_pps) - -    def set_tick_period(self, tk_idx, period_ns): -        """ -        Set the time per tick in nanoseconds (tick period) - -        Arguments: -        tk_idx: Index of timekeeper -        period_ns: Period in nanoseconds -        """ -        self.mboard_regs_control.set_tick_period(tk_idx, period_ns) -      def get_clocks(self):          """          Gets the RFNoC-related clocks present in the FPGA design @@ -1100,7 +1031,6 @@ class n3xx(ZynqComponents, PeriphManagerBase):              },              {                  'name': 'bus_clk', -                'freq': str(200e6), +                'freq': str(N3XX_BUS_CLK),              }          ] - diff --git a/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py b/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py index 9b83816c4..ef2372e62 100644 --- a/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py +++ b/mpm/python/usrp_mpm/periph_manager/n3xx_periphs.py @@ -1,5 +1,6 @@  #  # Copyright 2018 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Brand  #  # SPDX-License-Identifier: GPL-3.0-or-later  # @@ -7,12 +8,11 @@  N3xx peripherals  """ -import datetime  from usrp_mpm import lib  from usrp_mpm.sys_utils.sysfs_gpio import SysFSGPIO, GPIOBank -from usrp_mpm.sys_utils.uio import UIO  from usrp_mpm.sys_utils import i2c_dev  from usrp_mpm.chips.ds125df410 import DS125DF410 +from usrp_mpm.periph_manager.common import MboardRegsCommon  # Map register values to SFP transport types  N3XX_SFP_TYPES = { @@ -160,41 +160,20 @@ class BackpanelGPIO(GPIOBank):              0x7, # ddr          ) -class MboardRegsControl(object): +class MboardRegsControl(MboardRegsCommon):      """      Control the FPGA Motherboard registers      """ -    # Motherboard registers -    MB_COMPAT_NUM   = 0x0000 -    MB_DATESTAMP    = 0x0004 -    MB_GIT_HASH     = 0x0008 -    MB_SCRATCH      = 0x000C -    MB_DEVICE_ID    = 0x0010 -    MB_RFNOC_INFO   = 0x0014 -    MB_CLOCK_CTRL   = 0x0018 -    MB_XADC_RB      = 0x001C -    MB_BUS_CLK_RATE = 0x0020 -    MB_BUS_COUNTER  = 0x0024 -    MB_SFP0_INFO    = 0x0028 -    MB_SFP1_INFO    = 0x002C -    MB_GPIO_MASTER  = 0x0030 -    MB_GPIO_RADIO_SRC  = 0x0034 -    MB_NUM_TIMEKEEPERS = 0x0048 -    # Timekeeper registers -    MB_TIME_NOW_LO         = 0x1000 -    MB_TIME_NOW_HI         = 0x1004 -    MB_TIME_EVENT_LO       = 0x1008 -    MB_TIME_EVENT_HI       = 0x100C -    MB_TIME_CTRL           = 0x1010 -    MB_TIME_LAST_PPS_LO    = 0x1014 -    MB_TIME_LAST_PPS_HI    = 0x1018 -    MB_TIME_BASE_PERIOD_LO = 0x101C -    MB_TIME_BASE_PERIOD_HI = 0x1020 -    MB_TIMEKEEPER_OFFSET   = 12 - -    # Bitfield locations for the MB_RFNOC_INFO register. -    MB_RFNOC_INFO_PROTO_VER = 0 -    MB_RFNOC_INFO_CHDR_WIDTH = 16 +    # pylint: disable=bad-whitespace +    # Motherboard registers (on top of the ones in MboardRegsCommon) +    MB_CLOCK_CTRL     = 0x0018 +    MB_XADC_RB        = 0x001C +    MB_BUS_CLK_RATE   = 0x0020 +    MB_BUS_COUNTER    = 0x0024 +    MB_SFP0_INFO      = 0x0028 +    MB_SFP1_INFO      = 0x002C +    MB_GPIO_MASTER    = 0x0030 +    MB_GPIO_RADIO_SRC = 0x0034      # Bitfield locations for the MB_CLOCK_CTRL register.      MB_CLOCK_CTRL_PPS_SEL_INT_10 = 0 # pps_sel is one-hot encoded! @@ -207,66 +186,10 @@ class MboardRegsControl(object):      MB_CLOCK_CTRL_MEAS_CLK_RESET = 12 # set to 1 to reset mmcm, default is 0      MB_CLOCK_CTRL_MEAS_CLK_LOCKED = 13 # locked indication for meas_clk mmcm      MB_CLOCK_CTRL_DISABLE_REF_CLK = 16 # to disable the ref_clk, write a '1' +    # pylint: enable=bad-whitespace      def __init__(self, label, log): -        self.log = log -        self.regs = UIO( -            label=label, -            read_only=False -        ) -        self.poke32 = self.regs.poke32 -        self.peek32 = self.regs.peek32 - -    def get_compat_number(self): -        """get FPGA compat number - -        This function reads back FPGA compat number. -        The return is a tuple of -        2 numbers: (major compat number, minor compat number ) -        """ -        with self.regs: -            compat_number = self.peek32(self.MB_COMPAT_NUM) -        minor = compat_number & 0xff -        major = (compat_number>>16) & 0xff -        return (major, minor) - -    def set_device_id(self, device_id): -        """ -        Set device ID -        """ -        with self.regs: -            self.log.trace("Writing MB_DEVICE_ID with 0x{:08X}".format(device_id)) -            return self.poke32(self.MB_DEVICE_ID, device_id) - -    def get_device_id(self): -        """ -        Get device ID -        """ -        with self.regs: -            reg_val = self.peek32(self.MB_DEVICE_ID) -            device_id = reg_val & 0x0000ffff -            self.log.trace("Read MB_DEVICE_ID 0x{:08X}".format(device_id)) -            return device_id - -    def get_proto_ver(self): -        """ -        Return RFNoC protocol version -        """ -        with self.regs: -            reg_val = self.peek32(self.MB_RFNOC_INFO) -            proto_ver = (reg_val & 0x0000ffff) >> self.MB_RFNOC_INFO_PROTO_VER -            self.log.trace("Read RFNOC_PROTO_VER 0x{:08X}".format(proto_ver)) -            return proto_ver; - -    def get_chdr_width(self): -        """ -        Return RFNoC CHDR width -        """ -        with self.regs: -            reg_val = self.peek32(self.MB_RFNOC_INFO) -            chdr_width = (reg_val & 0xffff0000) >> self.MB_RFNOC_INFO_CHDR_WIDTH -            self.log.trace("Read RFNOC_CHDR_WIDTH 0x{:08X}".format(chdr_width)) -            return chdr_width +        MboardRegsCommon.__init__(self, label, log)      def set_fp_gpio_master(self, value):          """set driver for front panel GPIO @@ -308,43 +231,6 @@ class MboardRegsControl(object):          with self.regs:              return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xffffff -    def get_build_timestamp(self): -        """ -        Returns the build date/time for the FPGA image. -        The return is datetime string with the  ISO 8601 format -        (YYYY-MM-DD HH:MM:SS.mmmmmm) -        """ -        with self.regs: -            datestamp_rb = self.peek32(self.MB_DATESTAMP) -        if datestamp_rb > 0: -            dt_str = datetime.datetime( -                year=((datestamp_rb>>17)&0x3F)+2000, -                month=(datestamp_rb>>23)&0x0F, -                day=(datestamp_rb>>27)&0x1F, -                hour=(datestamp_rb>>12)&0x1F, -                minute=(datestamp_rb>>6)&0x3F, -                second=((datestamp_rb>>0)&0x3F)) -            self.log.trace("FPGA build timestamp: {}".format(str(dt_str))) -            return str(dt_str) -        else: -            # Compatibility with FPGAs without datestamp capability -            return '' - -    def get_git_hash(self): -        """ -        Returns the GIT hash for the FPGA build. -        The return is a tuple of -        2 numbers: (short git hash, bool: is the tree dirty?) -        """ -        with self.regs: -            git_hash_rb = self.peek32(self.MB_GIT_HASH) -        git_hash = git_hash_rb & 0x0FFFFFFF -        tree_dirty = ((git_hash_rb & 0xF0000000) > 0) -        dirtiness_qualifier = 'dirty' if tree_dirty else 'clean' -        self.log.trace("FPGA build GIT Hash: {:07x} ({})".format( -            git_hash, dirtiness_qualifier)) -        return (git_hash, dirtiness_qualifier) -      def set_time_source(self, time_source, ref_clk_freq):          """          Set time source | 
