Data Watch-point and Trace unit(DWT) interface.

Files at this revision

API Documentation at this revision

Comitter:
YasuhiroKawai
Date:
Sun Oct 08 05:51:12 2017 +0000
Commit message:
Initial revision

Changed in this revision

Dwt.cpp Show annotated file Show diff for this revision Revisions of this file
Dwt.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Dwt.cpp	Sun Oct 08 05:51:12 2017 +0000
@@ -0,0 +1,97 @@
+
+#include <mbed.h>
+#include "Dwt.h"
+
+const uint32_t Dwt::DWT_REGS_ADDR = 0xe0001000;
+const uint32_t Dwt::SCB_DEMCR_ADDR = 0xe000edfc;
+
+const uint32_t Dwt::NUMCOMP_POS = 28;
+const uint32_t Dwt::NUMCOMP_MASK = (0xfU << Dwt::NUMCOMP_POS);
+const uint32_t Dwt::NOTRCPKT  = (1 << 27);
+const uint32_t Dwt::NOEXTTRIG = (1 << 26);
+const uint32_t Dwt::NOCYCCNT  = (1 << 25);
+const uint32_t Dwt::NOPRFCNT  = (1 << 24);
+
+const uint32_t Dwt::CYCEVTENA   = (1 << 22);
+const uint32_t Dwt::FOLDEVTENA  = (1 << 21);
+const uint32_t Dwt::LSUEVTENA   = (1 << 20);
+const uint32_t Dwt::SLEEPEVTENA = (1 << 19);
+const uint32_t Dwt::EXCEVTENA   = (1 << 18);
+const uint32_t Dwt::CPIEVTENA   = (1 << 17);
+const uint32_t Dwt::EXCTRCENA   = (1 << 16);
+const uint32_t Dwt::PCSAMPLENA  = (1 << 12);
+const uint32_t Dwt::CYCCNTENA   = (1 <<  0);
+
+const uint32_t Dwt::TRCENA      = (1 << 24);
+
+const uint32_t Dwt::EVENA_MASK = Dwt::CYCEVTENA | Dwt::FOLDEVTENA | Dwt::LSUEVTENA | Dwt::SLEEPEVTENA |
+                                 Dwt::EXCEVTENA | Dwt::CPIEVTENA  | Dwt::EXCTRCENA | Dwt::PCSAMPLENA |
+                                 Dwt::CYCCNTENA;
+
+
+
+Dwt::Dwt()
+{
+    _regs = (volatile dwt_regs_t *)DWT_REGS_ADDR;
+    _scb_demcr_regs = (volatile uint32_t *)SCB_DEMCR_ADDR;
+}
+
+bool
+Dwt::isTRCPKT_Available()
+{
+    return((_regs->DWT_CTRL & NOTRCPKT) == 0);    
+}
+
+
+bool
+Dwt::isEXTTRIG_Available()
+{
+    return((_regs->DWT_CTRL & NOEXTTRIG) == 0);    
+}
+
+bool
+Dwt::isCYCCNT_Available()
+{
+    return((_regs->DWT_CTRL & NOCYCCNT) == 0);    
+}
+
+bool
+Dwt::isPRFCNT_Available()
+{
+    return((_regs->DWT_CTRL & NOPRFCNT) == 0);    
+}
+
+void
+Dwt::enableCYCCNT()
+{
+    *_scb_demcr_regs |= TRCENA;
+}
+
+void
+Dwt::disableCYCCNT()
+{
+    *_scb_demcr_regs &= ~TRCENA;
+}
+
+void
+Dwt::setEvent(uint32_t ev)
+{
+    uint32_t tmp;
+    tmp = _regs->DWT_CTRL;
+    tmp &= ~EVENA_MASK;
+    tmp |= ev & EVENA_MASK;
+    _regs->DWT_CTRL = tmp;
+}
+
+/// ICNT = CNT_CYCLES + CNT_FOLD - (CNT_LSU + CNT_EXC + CNT_SLEEP + CNT_CPI)
+uint32_t
+Dwt::getInstructionCount()
+{
+    uint32_t cnt_cycles = getCYCCNT();
+    uint32_t cnt_fold   = getFOLDCNT();
+    uint32_t cnt_lsu    = getLSUCNT();
+    uint32_t cnt_exc    = getEXCCNT();
+    uint32_t cnt_sleep  = getSLEEPCNT();
+    uint32_t cnt_cpi    = getCPICNT();
+    return(cnt_cycles + cnt_fold - (cnt_lsu + cnt_exc + cnt_sleep + cnt_cpi));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Dwt.h	Sun Oct 08 05:51:12 2017 +0000
@@ -0,0 +1,177 @@
+/**
+ * DWT class
+ */
+#ifndef DWT_H
+#define DWT_H
+
+/**
+ * The Data Watchpoint and Trace unit intarface
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "Dwt.h"
+ * 
+ * Serial pc(SERIAL_TX, SERIAL_RX);
+ * Dwt dwt;
+ * 
+ * int main() {
+ *     uint32_t t;
+ *     uint32_t n;
+ *
+ *     dwt.enableCYCCNT();
+ *     dwt.resetCYCCNT();
+ *     dwt.startCount();
+ *     <Write some codes to measure the execution cycle here.>
+ *     dwt.stopCount();
+ *     t = dwt.getCYCCNT();
+ *     n = dwt.getInstructionCount();
+ *     pc.printf("%d cycles, %d instructions.\n", t, n);
+ * }
+ * @endcode
+ */
+#define DWT_MAJOR_VERSION   (0)
+#define DWT_MINOR_VERSION   (1)
+
+class Dwt 
+{
+    /**
+     * The Data Watchpoint and Trace unit intarface
+     */
+public:
+
+    /** 
+     * Create a DWT interface
+     */
+    Dwt();
+    
+     /// Returns whether the implementation supports trace sampling and exception tracing.
+     /// true  : Trace sampling and exception tracing supported.
+     /// false : Trace sampling and exception tracing not supported.
+    bool isTRCPKT_Available();
+    /// Returns whether the implementation includes external match signals, CMPMATCH[N].
+    bool isEXTTRIG_Available();
+    /// Returns whether the implementation supports a cycle counter.
+    bool isCYCCNT_Available();
+    /// Returns whether the implementation supports the profiling counters.
+    bool isPRFCNT_Available();
+    
+    void enableCYCCNT();
+    void disableCYCCNT();
+    inline void startCYCCNT() {
+        _regs->DWT_CTRL |= CYCCNTENA;
+    }
+    inline void stopCYCCNT() {
+        _regs->DWT_CTRL &= ~CYCCNTENA;
+    }
+    inline void resetCYCCNT() {
+        _regs->DWT_CYCCNT = 0;
+    }
+    inline uint32_t getCYCCNT() {
+        return(_regs->DWT_CYCCNT);
+    }
+    inline uint32_t readDwtCtrl() {
+        return(_regs->DWT_CTRL);
+    }
+    inline uint32_t getNumComp() {
+        return((_regs->DWT_CTRL & NUMCOMP_MASK) >> NUMCOMP_POS);
+    }
+    void setEvent(uint32_t ev);
+    inline uint32_t getEvent() {
+        return(_regs->DWT_CTRL & EVENA_MASK);
+    }
+    /// Returns additional cycles required to execute multicycle instructions and 
+    /// instruction fetch stalls.
+    inline uint32_t getCPICNT() {
+        return(_regs->DWT_CPICNT);
+    }
+    /// Returns the total cycles spent in exception processing.
+    inline uint32_t getEXCCNT() {
+        return(_regs->DWT_EXCCNT);
+    }
+    /// Returns the total number of cycles that the processor is sleeping.
+    inline uint32_t getSLEEPCNT() {
+        return(_regs->DWT_SLEEPCNT);
+    }
+    /// Returns the additional cycles required to execute all load or 
+    /// store instructions.
+    inline uint32_t getLSUCNT() {
+        return(_regs->DWT_LSUCNT);
+    }
+    /// Returns the number of instructions that takes 0 cycles.
+    inline uint32_t getFOLDCNT() {
+        return(_regs->DWT_FOLDCNT);
+    }
+    /// start all counters
+    inline void startCount() {
+        _regs->DWT_CTRL |= (Dwt::CPIEVTENA | Dwt::EXCEVTENA | Dwt::SLEEPEVTENA | 
+                            Dwt::LSUEVTENA | Dwt::FOLDEVTENA | Dwt::CYCCNTENA);
+    }
+    ///  stop all counters
+    inline void stopCount() {
+        _regs->DWT_CTRL &= ~(Dwt::CPIEVTENA | Dwt::EXCEVTENA | Dwt::SLEEPEVTENA | 
+                             Dwt::LSUEVTENA | Dwt::FOLDEVTENA | Dwt::CYCCNTENA);
+    }
+    /// Returns number of executed instructions.
+    uint32_t getInstructionCount();
+private:
+    typedef struct {
+        uint32_t DWT_COMP;      ///< Provides a reference value for use by 
+                                ///< comparator n.
+        uint32_t DWT_MASK;      ///< Provides the size of the ignore mask applied
+                                ///< to the access address for address range
+                                ///< matching by comparator n.
+        uint32_t DWT_FUNCTION;  ///< Controls the operation of comparator n.
+        uint32_t reserved;
+    } dwt_cmp_regs_t;
+
+    typedef struct {
+        uint32_t DWT_CTRL;      ///< Control register
+        uint32_t DWT_CYCCNT;    ///< Shows or sets the value of the processor 
+                                ///< cycle counter, CYCCNT.
+        uint32_t DWT_CPICNT;    ///< Counts additional cycles required to execute 
+                                ///< multicycle instructions and instruction 
+                                ///< fetch stalls.
+        uint32_t DWT_EXCCNT;    ///< Counts the total cycles spent in exception 
+                                ///< processing.
+        uint32_t DWT_SLEEPCNT;  ///< Counts the total number of cycles that the 
+                                ///< processor is sleeping.
+        uint32_t DWT_LSUCNT;    ///< Increments on the additional cycles required
+                                ///< to execute all load or store instructions.
+        uint32_t DWT_FOLDCNT;   ///< Increments on each instruction that takes 0 
+                                ///< cycles.
+        uint32_t DWT_PCSR;      ///< Samples the current value of the program 
+                                ///< counter.
+        dwt_cmp_regs_t regs[16];
+    } dwt_regs_t;
+    
+    static const uint32_t DWT_REGS_ADDR;
+    static const uint32_t SCB_DEMCR_ADDR;
+
+    static const uint32_t NUMCOMP_POS;
+    static const uint32_t NUMCOMP_MASK;
+    static const uint32_t NOTRCPKT;
+    static const uint32_t NOEXTTRIG;
+    static const uint32_t NOCYCCNT;
+    static const uint32_t NOPRFCNT;
+public:
+    static const uint32_t CYCEVTENA;    /// Enables POSTCNT underflow Event counter packets generation.
+    static const uint32_t FOLDEVTENA;   /// Enables generation of the Folded-instruction counter overflow event. 
+    static const uint32_t LSUEVTENA;    /// Enables generation of the LSU counter overflow event.
+    static const uint32_t SLEEPEVTENA;  /// Enables generation of the Sleep counter overflow event.
+    static const uint32_t EXCEVTENA;    /// Enables generation of the Exception overhead counter overflow event:
+    static const uint32_t CPIEVTENA;    /// Enables generation of the CPI counter overflow event.
+    static const uint32_t EXCTRCENA;    /// Enables generation of the CPI counter overflow event.
+    static const uint32_t PCSAMPLENA;   /// Enables use of POSTCNT counter as a timer for Periodic PC sample packet generation.
+    static const uint32_t CYCCNTENA;    /// Enables CYCCNT.
+
+private:
+    static const uint32_t TRCENA;
+    static const uint32_t EVENA_MASK;
+
+private:    
+    volatile dwt_regs_t *_regs;
+    volatile uint32_t *_scb_demcr_regs;
+};
+
+
+#endif /* DWT_H */