from com.arm.debug.dtsl.configurations import DTSLv1
from com.arm.debug.dtsl.components import FormatterMode
from com.arm.debug.dtsl.components import APBAP
from com.arm.debug.dtsl.components import AxBMemAPAccessor
from com.arm.debug.dtsl.components import CortexM_AHBAP
from com.arm.debug.dtsl.components import AHBCortexMMemAPAccessor
from com.arm.debug.dtsl.components import Device
from com.arm.debug.dtsl.configurations.options import IIntegerOption
from com.arm.debug.dtsl.components import CSTMC
from com.arm.debug.dtsl.components import TMCETBTraceCapture
from com.arm.debug.dtsl.components import ETRTraceCapture
from com.arm.debug.dtsl.components import DSTREAMSTStoredTraceCapture
from com.arm.debug.dtsl.components import DSTREAMTraceCapture
from com.arm.debug.dtsl.components import CSCTI
from com.arm.debug.dtsl.components import ETMv4TraceSource
from com.arm.debug.dtsl.components import CSTPIU
from com.arm.debug.dtsl.components import CSFunnel
from com.arm.debug.dtsl.components import STMTraceSource
from com.arm.debug.dtsl.components import CTISyncSMPDevice
from com.arm.debug.dtsl.components import DeviceCluster
from com.arm.debug.dtsl.configurations import TimestampInfo
from com.arm.debug.dtsl.interfaces import IARMCoreTraceSource

coreNames = ["Cortex-A53_0", "Cortex-A53_1", "Cortex-A53_2", "Cortex-A53_3", "Cortex-A73_0", "Cortex-A73_1", "Cortex-A73_2", "Cortex-A73_3", "Cortex-M3"]
dapIndices = [0, 0, 0, 0, 0, 0, 0, 0, 0]
ctiNames = ["CSCTI_Cortex-A53_0", "CSCTI_Cortex-A53_1", "CSCTI_Cortex-A53_2", "CSCTI_Cortex-A53_3", "CSCTI_7", "CSCTI_8", "CSCTI_9", "CSCTI_10", None]
ctiCoreTriggers = [1, 1, 1, 1, 1, 1, 1, 1, None]
ctiMacrocellTriggers = [6, 6, 6, 6, 6, 6, 6, 6, None]
macrocellNames = ["CSETM_Cortex-A53_0", "CSETM_Cortex-A53_1", "CSETM_Cortex-A53_2", "CSETM_Cortex-A53_3", "CSETM_3", "CSETM_4", "CSETM_5", "CSETM_6", None, "CSSTM"]
macrocellNames_cortexA53 = ["CSETM_Cortex-A53_0", "CSETM_Cortex-A53_1", "CSETM_Cortex-A53_2", "CSETM_Cortex-A53_3"]
macrocellNames_cortexA73 = ["CSETM_3", "CSETM_4", "CSETM_5", "CSETM_6"]
funnelNames = [["CSTFunnel_0", "CSTFunnel_1"], ["CSTFunnel_0", "CSTFunnel_1"], ["CSTFunnel_0","CSTFunnel_1"], ["CSTFunnel_0","CSTFunnel_1"], ["CSTFunnel_0","CSTFunnel_2"], ["CSTFunnel_0","CSTFunnel_2"], ["CSTFunnel_0","CSTFunnel_2"], ["CSTFunnel_0","CSTFunnel_2"], None, "CSTFunnel_0"]
funnelPorts = [[0, 0], [0, 1], [0, 2], [0, 3], [0, 0], [0, 1], [0, 2], [0, 3], None, 4]
clusterNames = ["Cortex-A53_SMP_0", "Cortex-A73_SMP_0"]
clusterCores = [["Cortex-A53_0", "Cortex-A53_1", "Cortex-A53_2", "Cortex-A53_3"], ["Cortex-A73_0", "Cortex-A73_1", "Cortex-A73_2", "Cortex-A73_3"]]
coreNames_cortexA53 = ["Cortex-A53_0", "Cortex-A53_1", "Cortex-A53_2", "Cortex-A53_3"]
coreNames_cortexA73 = ["Cortex-A73_0", "Cortex-A73_1", "Cortex-A73_2", "Cortex-A73_3"]
coreNames_cortexM3 = ["Cortex-M3"]

TRACE_RANGE_DESCRIPTION = '''Limit trace capture to the specified range. This is useful for restricting trace capture to an OS (e.g. Linux kernel)'''
CTM_CHANNEL_SYNC_STOP = 2  # Use channel 2 for sync stop
CTM_CHANNEL_SYNC_START = 1  # Use channel 1 for sync start
CTM_CHANNEL_TRACE_TRIGGER = 3  # Use channel 3 for trace triggers

# Import core specific functions
import a53_rams
import a73_rams

class DtslScript(DTSLv1):
    @staticmethod
    def getOptionList():
        return [
            DTSLv1.tabSet("options", "Options", childOptions=
                [DTSLv1.tabPage("Cortex-A53_SMP_0", "Cortex-A53", childOptions=[
                    DTSLv1.enumOption('traceCapture', 'Trace capture method', defaultValue="none",
                        values = [("none", "None"), ("CSTMC_0", "System Memory Trace Buffer (CSTMC_0/ETR)"), ("CSTMC_1", "On Chip Trace Buffer (CSTMC_1/ETF_Global)"), ("CSTMC_2", "On Chip Trace Buffer (CSTMC_2/ETF_A53)"), ("DSTREAM", "DSTREAM 4GB Trace Buffer")]),
                    DTSLv1.infoElement("traceOpts", "Trace Options", childOptions=[
                        DTSLv1.integerOption('timestampFrequency', 'Timestamp frequency', defaultValue=25000000, isDynamic=False, description="This value will be used to set the Counter Base Frequency ID Register of the Timestamp generator.\nIt represents the number of ticks per second and is used to translate the timestamp value reported into a number of seconds.\nNote that changing this value may not result in a change in the observed frequency."),
                    ]),
                    DTSLv1.infoElement("offChip", "Off-Chip Trace", childOptions=[
                        DTSLv1.enumOption('tpiuPortWidth', 'TPIU Port Width', defaultValue="16",
                            values = [("1", "1 bit"), ("2", "2 bit"), ("3", "3 bit"), ("4", "4 bit"), ("5", "5 bit"), ("6", "6 bit"), ("7", "7 bit"), ("8", "8 bit"), ("9", "9 bit"), ("10", "10 bit"), ("11", "11 bit"), ("12", "12 bit"), ("13", "13 bit"), ("14", "14 bit"), ("15", "15 bit"), ("16", "16 bit")], isDynamic=False),
                    ]),
                    DTSLv1.booleanOption('coreTrace', 'Enable Cortex-A53 core trace', defaultValue=False,
                        childOptions =
                            # Allow each source to be enabled/disabled individually
                            [ DTSLv1.booleanOption('Cortex-A53_SMP_0_%d' % core, "Enable " + clusterCores[0][core] + " trace", defaultValue=True)
                            for core in range(len(clusterCores[0])) ] +
                            [ DTSLv1.booleanOption('timestamp', "Enable ETM Timestamps", description="Controls the output of timestamps into the ETM output streams", defaultValue=True) ] +
                            [ DTSLv1.booleanOption('contextIDs', "Enable ETM Context IDs", description="Controls the output of context ID values into the ETM output streams", defaultValue=True)
                            ] +
                            [ ETMv4TraceSource.cycleAccurateOption(DtslScript.getTraceMacrocellsForCluster("Cortex-A53_SMP_0"))] +
                            [ # Trace range selection (e.g. for linux kernel)
                            DTSLv1.booleanOption('traceRange', 'Trace capture range',
                                description=TRACE_RANGE_DESCRIPTION,
                                defaultValue = False,
                                childOptions = [
                                    DTSLv1.integerOption('start', 'Start address',
                                        description='Start address for trace capture',
                                        defaultValue=0,
                                        display=IIntegerOption.DisplayFormat.HEX),
                                    DTSLv1.integerOption('end', 'End address',
                                        description='End address for trace capture',
                                        defaultValue=0xFFFFFFFF,
                                        display=IIntegerOption.DisplayFormat.HEX)
                                ])
                            ]
                        ),
                ])]
                +[DTSLv1.tabPage("Cortex-A73_SMP_0", "Cortex-A73", childOptions=[
                    DTSLv1.enumOption('traceCapture', 'Trace capture method', defaultValue="none",
                        values = [("none", "None"), ("CSTMC_0", "System Memory Trace Buffer (CSTMC_0/ETR)"), ("CSTMC_1", "On Chip Trace Buffer (CSTMC_1/ETF_Global)"), ("CSTMC_3", "On Chip Trace Buffer (CSTMC_3/ETF_A73)"), ("DSTREAM", "DSTREAM 4GB Trace Buffer")]),
                    DTSLv1.infoElement("traceOpts", "Trace Options", childOptions=[
                        DTSLv1.integerOption('timestampFrequency', 'Timestamp frequency', defaultValue=25000000, isDynamic=False, description="This value will be used to set the Counter Base Frequency ID Register of the Timestamp generator.\nIt represents the number of ticks per second and is used to translate the timestamp value reported into a number of seconds.\nNote that changing this value may not result in a change in the observed frequency."),
                    ]),
                    DTSLv1.infoElement("offChip", "Off-Chip Trace", childOptions=[
                        DTSLv1.enumOption('tpiuPortWidth', 'TPIU Port Width', defaultValue="16",
                            values = [("1", "1 bit"), ("2", "2 bit"), ("3", "3 bit"), ("4", "4 bit"), ("5", "5 bit"), ("6", "6 bit"), ("7", "7 bit"), ("8", "8 bit"), ("9", "9 bit"), ("10", "10 bit"), ("11", "11 bit"), ("12", "12 bit"), ("13", "13 bit"), ("14", "14 bit"), ("15", "15 bit"), ("16", "16 bit")], isDynamic=False),
                    ]),                    
                    DTSLv1.booleanOption('coreTrace', 'Enable Cortex-A73 core trace', defaultValue=False,
                        childOptions =
                            # Allow each source to be enabled/disabled individually
                            [ DTSLv1.booleanOption('Cortex-A73_SMP_0_%d' % core, "Enable " + clusterCores[1][core] + " trace", defaultValue=True)
                            for core in range(len(clusterCores[1])) ] +
                            [ DTSLv1.booleanOption('timestamp', "Enable ETM Timestamps", description="Controls the output of timestamps into the ETM output streams", defaultValue=True) ] +
                            [ DTSLv1.booleanOption('contextIDs', "Enable ETM Context IDs", description="Controls the output of context ID values into the ETM output streams", defaultValue=True)
                            ] +
                            [ ETMv4TraceSource.cycleAccurateOption(DtslScript.getTraceMacrocellsForCluster("Cortex-A73_SMP_0"))] +
                            [ # Trace range selection (e.g. for linux kernel)
                            DTSLv1.booleanOption('traceRange', 'Trace capture range',
                                description=TRACE_RANGE_DESCRIPTION,
                                defaultValue = False,
                                childOptions = [
                                    DTSLv1.integerOption('start', 'Start address',
                                        description='Start address for trace capture',
                                        defaultValue=0,
                                        display=IIntegerOption.DisplayFormat.HEX),
                                    DTSLv1.integerOption('end', 'End address',
                                        description='End address for trace capture',
                                        defaultValue=0xFFFFFFFF,
                                        display=IIntegerOption.DisplayFormat.HEX)
                                ])
                            ]
                        ),
                ])]
                +[DTSLv1.tabPage("ETR", "ETR", childOptions=[
                    DTSLv1.booleanOption('etrBuffer0', 'Configure the system memory trace buffer to be used by the CSTMC_0/ETR device', defaultValue=False,
                        childOptions = [
                            DTSLv1.integerOption('start', 'Start address',
                            description='Start address of the system memory trace buffer to be used by the CSTMC_0/ETR device',
                            defaultValue=0x00100000,
                            display=IIntegerOption.DisplayFormat.HEX),
                            DTSLv1.integerOption('size', 'Size in bytes',
                            description='Size of the system memory trace buffer in bytes',
                            defaultValue=0x8000,
                            isDynamic=True,
                            display=IIntegerOption.DisplayFormat.HEX),
                            DTSLv1.booleanOption('scatterGather', 'Enable scatter-gather mode',
                            defaultValue=False,
                            description='When enabling scatter-gather mode, the start address of the on-chip trace buffer must point to a configured scatter-gather table')
                        ]
                    ),
                ])]
                +[DTSLv1.tabPage("stm", "STM", childOptions=[
                    DTSLv1.booleanOption('CSSTM', 'Enable CSSTM trace', defaultValue=False),
                ])]
                +[DTSLv1.tabPage("rams", "Cache RAMs", childOptions=[
                    # Turn cache debug mode on/off
                    DTSLv1.booleanOption('cacheDebug', 'Cache debug mode',
                                         description='Turning cache debug mode on enables reading the cache RAMs. Enabling it may adversely impact debug performance.',
                                         defaultValue=False, isDynamic=True),
                    DTSLv1.booleanOption('cachePreserve', 'Preserve cache contents in debug state',
                                         description='Preserve the contents of caches while the core is stopped.',
                                         defaultValue=False, isDynamic=True),
                ])]
            )
        ]
    
    def __init__(self, root):
        DTSLv1.__init__(self, root)
        
        '''Do not add directly to this list - first check if the item you are adding is already present'''
        self.mgdPlatformDevs = []
        
        # Tracks which devices are managed when a trace mode is enabled
        self.mgdTraceDevs = {}
        
        # Locate devices on the platform and create corresponding objects
        self.discoverDevices()
        
        self.exposeCores()
        
        self.traceRangeIDs = {}
        
        self.setupCTISyncSMP()
        
        self.setupBigLittle()
        
        self.setManagedDeviceList(self.mgdPlatformDevs)
        
        self.setETFTraceEnabled(self.ETF0Trace, False)
        self.setETFTraceEnabled(self.ETF1Trace, False)
        self.setETFTraceEnabled(self.ETF2Trace, False)
        self.setETRTraceEnabled(self.ETR0, False)
        self.setDSTREAMTraceEnabled(False)
    # +----------------------------+
    # | Target dependent functions |
    # +----------------------------+
    
    def discoverDevices(self):
        '''Find and create devices'''
        
        self.APBs = []
        self.AHB_Ms = []
        
        ap = APBAP(self, self.findDevice("CSMEMAP_0"), "APB_0")
        self.mgdPlatformDevs.append(ap)
        self.APBs.append(ap)
        
        ap = CortexM_AHBAP(self, self.findDevice("CSMEMAP_1"), "AHB_M_0")
        self.mgdPlatformDevs.append(ap)
        self.AHB_Ms.append(ap)
        
        # Trace start/stop CTI 0
        self.OutCTI0 = CSCTI(self, self.findDevice("CSCTI_0"), "CSCTI_0")
        
        
        # The ATB stream ID which will be assigned to trace sources.
        streamID = 1
        
        # STM -- CSSTM
        self.STM0 = self.createSTM("CSSTM", streamID, "CSSTM")
        streamID += 1
        
        # For future use, store a map of core types and cluster names against created devices
        self.macrocells = {}
        self.macrocells["cortexA53"] = []
        self.macrocells["cortexA73"] = []
        self.macrocells["cortexM3"] = []
        self.macrocells["Cortex-A53_SMP_0"] = []
        self.macrocells["Cortex-A73_SMP_0"] = []
        
        self.cortexM3cores = []
        for core in range(len(coreNames_cortexM3)):
            # Create core
            coreDevice = Device(self, self.findDevice(coreNames_cortexM3[core]), coreNames_cortexM3[core])
            self.cortexM3cores.append(coreDevice)
            
        self.cortexA53cores = []
        for core in range(len(coreNames_cortexA53)):
            # Create core
            coreDevice = a53_rams.A53CoreDevice(self, self.findDevice(coreNames_cortexA53[core]), coreNames_cortexA53[core])
            self.cortexA53cores.append(coreDevice)
            
            # Create Trace Macrocell (if a macrocell exists for this core - disabled by default - will enable with option)
            tmDev = self.getMacrocellNameForCore(coreNames_cortexA53[core])
            if not tmDev == None:
                tm = ETMv4TraceSource(self, self.findDevice(tmDev), streamID, tmDev)
                streamID += 2
                tm.setEnabled(False)
                self.macrocells["cortexA53"].append(tm)
                self.addMacrocellsToClusterList(coreNames[core], tm)
            
        self.cortexA73cores = []
        for core in range(len(coreNames_cortexA73)):
            # Create core
            coreDevice = a73_rams.A73CoreDevice(self, self.findDevice(coreNames_cortexA73[core]), coreNames_cortexA73[core])
            self.cortexA73cores.append(coreDevice)
            
            # Create Trace Macrocell (if a macrocell exists for this core - disabled by default - will enable with option)
            tmDev = self.getMacrocellNameForCore(coreNames_cortexA73[core])
            if not tmDev == None:
                tm = ETMv4TraceSource(self, self.findDevice(tmDev), streamID, tmDev)
                streamID += 2
                tm.setEnabled(False)
                self.macrocells["cortexA73"].append(tm)
                self.addMacrocellsToClusterList(coreNames[core], tm)
            
        # Create all the CTIs which are associated with cores
        for i in range (len(ctiNames)):
            if not ctiNames[i] is None:
                coreCTI = CSCTI(self, self.findDevice(ctiNames[i]), ctiNames[i])
                # Automatically handle connection to CTIs
                self.mgdPlatformDevs.append(coreCTI)
        
        # ETR 0
        self.ETR0 = ETRTraceCapture(self, self.findDevice("CSTMC_0"), "CSTMC_0")
        
        # ETF 0
        self.ETF0 = CSTMC(self, self.findDevice("CSTMC_1"), "CSTMC_1")
        
        # ETF 0 trace capture
        self.ETF0Trace = TMCETBTraceCapture(self, self.ETF0, "CSTMC_1")
        
        # ETF 1
        self.ETF1 = CSTMC(self, self.findDevice("CSTMC_2"), "CSTMC_2")
        
        # ETF 1 trace capture
        self.ETF1Trace = TMCETBTraceCapture(self, self.ETF1, "CSTMC_2")
        
        # ETF 2
        self.ETF2 = CSTMC(self, self.findDevice("CSTMC_3"), "CSTMC_3")
        
        # ETF 2 trace capture
        self.ETF2Trace = TMCETBTraceCapture(self, self.ETF2, "CSTMC_3")
        
        # DSTREAM
        self.createDSTREAM()
        
        # TPIU
        self.TPIU = self.createTPIU("CSTPIU", "TPIU")
        
        # Funnel 0
        self.Funnel0 = self.createFunnel("CSTFunnel_0", "CSTFunnel_0")
        
        # Funnel 1
        self.Funnel1 = self.createFunnel("CSTFunnel_1", "CSTFunnel_1")
        
        # Funnel 2
        self.Funnel2 = self.createFunnel("CSTFunnel_2", "CSTFunnel_2")
        
    def registerFilters(self, core, dap):
        '''Register MemAP filters to allow access to the APs for the device'''
        if dap == 0:
            core.registerAddressFilters([
                AxBMemAPAccessor("APB_0", self.APBs[0], "APB bus accessed via AP 0 (CSMEMAP_0)"),
                AHBCortexMMemAPAccessor("AHB_M_0", self.AHB_Ms[0], "AHB-M bus accessed via AP 1 (CSMEMAP_1)"),
            ])
    
    def exposeCores(self):
        '''Ensure that cores have access to memory'''
        for i in range(len(coreNames)):
            core = self.getDeviceInterface(coreNames[i])
            self.registerFilters(core, dapIndices[i])
            self.addDeviceInterface(core)
        for core in self.cortexA53cores:
            a53_rams.registerInternalRAMs(core)
        for core in self.cortexA73cores:
            a73_rams.registerInternalRAMs(core)

    def setupETFTrace_Master(self, devices):
        '''Setup trace capture for master ETF'''
        # use continuous mode
        self.ETF0Trace.setFormatterMode(FormatterMode.CONTINUOUS)
        
        # register other trace components with ETF and register ETF with configuration
        self.ETF0Trace.setTraceComponentOrder([ self.Funnel0 ] + devices)
        self.addTraceCaptureInterface(self.ETF0Trace)
        
        # automatically handle connection/disconnection to trace components
        self.addManagedTraceDevices("CSTMC_1", [ self.Funnel0, self.ETF0Trace ] + devices)		

    def setupETFTrace_A53(self):
        '''Setup trace capture for A53_0 ETF'''
        # use continuous mode
        self.ETF1Trace.setFormatterMode(FormatterMode.CONTINUOUS)
        
        # register other trace components with ETF and register ETF with configuration
        self.ETF1Trace.setTraceComponentOrder([ self.Funnel1 ])
        self.addTraceCaptureInterface(self.ETF1Trace)
        
        # automatically handle connection/disconnection to trace components
        self.addManagedTraceDevices("CSTMC_2", [ self.Funnel1, self.ETF1Trace ])
    
    def setupETFTrace_A73(self):
        '''Setup trace capture for A73 ETF'''
        # use continuous mode
        self.ETF2Trace.setFormatterMode(FormatterMode.CONTINUOUS)
        
        # register other trace components with ETF and register ETF with configuration
        self.ETF2Trace.setTraceComponentOrder([ self.Funnel2 ])
        self.addTraceCaptureInterface(self.ETF2Trace)
        
        # automatically handle connection/disconnection to trace components
        self.addManagedTraceDevices("CSTMC_3", [ self.Funnel2, self.ETF2Trace ])
		
    def setupETFTrace(self, devices):
        self.setupETFTrace_Master(devices)
        self.setupETFTrace_A53()
        self.setupETFTrace_A73()	
    
    def setupETRTrace(self, devices):
        '''Setup ETR trace capture'''
        # use continuous mode
        self.ETR0.setFormatterMode(FormatterMode.CONTINUOUS)
        
        # register other trace components with ETR and register ETR with configuration
        self.ETR0.setTraceComponentOrder([ self.ETF0, self.Funnel0 ] + devices )
        self.addTraceCaptureInterface(self.ETR0)
        
        # automatically handle connection/disconnection to trace components
        self.addManagedTraceDevices("CSTMC_0", [ self.Funnel0, self.TPIU, self.ETF0, self.ETR0 ] + devices)

    def setupDSTREAMTrace(self, devices):
        '''Setup DSTREAM trace capture'''
        
        # configure the TPIU for continuous mode
        self.TPIU.setFormatterMode(FormatterMode.CONTINUOUS)
        
        # configure the DSTREAM for continuous trace
        self.DSTREAM.setTraceMode(DSTREAMTraceCapture.TraceMode.Continuous)
        
        # register other trace components
        self.DSTREAM.setTraceComponentOrder([ self.ETF0, self.Funnel0, self.TPIU ] + devices )
        
        # register the DSTREAM with the configuration
        self.addTraceCaptureInterface(self.DSTREAM)
        
        # automatically handle connection/disconnection to trace components
        self.addManagedTraceDevices("DSTREAM", [ self.Funnel0, self.TPIU, self.ETF0, self.DSTREAM ] + devices )		
    
    def setPortWidth(self, portWidth):
        self.TPIU.setPortSize(portWidth)
        self.DSTREAM.setPortWidth(portWidth)
    
    def enableFunnelPortForSource(self, source, enabled):
        '''Enable/Disable all pertinent funnel ports for a trace source'''
        sourceName = source.getName()
        for i in range(len(macrocellNames)):
            if sourceName == macrocellNames[i]:
                '''We may have a list of funnels to which the source is connected.'''
                if isinstance(funnelNames[i], list):
                    for j in range(len(funnelNames[i])):
                        '''Enable/Disable multiple connected funnel ports for this trace source.'''
                        self.setFunnelPortEnabled(funnelNames[i][j], funnelPorts[i][j], enabled)
                else:
                    '''Enable/Disable a single connected funnel port for this trace source.'''
                    self.setFunnelPortEnabled(funnelNames[i], funnelPorts[i], enabled)
    
    def getCTIForSource(self, source):
        '''Get the CTI and input/channel associated with a trace source
        return (None, None, None) if no associated CTI
        '''
        sourceName = source.getName()
        for i in range(len(coreNames)):
            if sourceName == macrocellNames[i]:
                if ctiMacrocellTriggers[i] is not None:
                    return (self.getDeviceInterface(ctiNames[i]), ctiMacrocellTriggers[i], CTM_CHANNEL_TRACE_TRIGGER)
        
        return (None, None, None)
    
    def getCTIForSink(self, sink):
        '''Get the CTI and output/channel associated with a trace sink
        return (None, None, None) if no associated CTI
        '''
        sinkNames = ["CSTPIU", "CSTMC_0", "CSTMC_1", "CSTMC_2", "CSTMC_3"]
        ctiNames = ["CSCTI_0", "CSCTI_0", "CSCTI_0", None, None]
        ctiTriggers = [3, 1, 1, None, None]
        
        sinkName = sink.getName()
        for i in range(len(sinkNames)):
            if sinkName == sinkNames[i]:
                return (self.getDeviceInterface(ctiNames[i]), ctiTriggers[i], CTM_CHANNEL_TRACE_TRIGGER)
        
        return (None, None, None)
    
    def setTraceSourceEnabled(self, source, enabled):
        '''Enable/disable a trace source'''
        source.setEnabled(enabled)
        self.enableFunnelPortForSource(source, enabled)
        self.enableCTIsForSource(source, enabled)
    
    def createTPIU(self, tpiuDev, name):
        tpiu = CSTPIU(self, self.findDevice(tpiuDev), name)
        # Disabled by default - will enable with option
        tpiu.setEnabled(False)
        return tpiu
    
    def setupCTISyncSMP(self):
        '''Create SMP device using CTI synchronization'''
        
        # Setup CTIs for sync start/stop
        for clusterIndex in range(len(clusterNames)):
            # Create SMP Device for this cluster
            dapIndex = self.getDapIndex(clusterCores[clusterIndex][0])
            coresInCluster = self.getDevicesFromNameList(clusterCores[clusterIndex])
            ctiInfo = self.getCTIInfoForCores(clusterCores[clusterIndex])
            smp = CTISyncSMPDevice(self, clusterNames[clusterIndex], coresInCluster, ctiInfo, CTM_CHANNEL_SYNC_START, CTM_CHANNEL_SYNC_STOP)
            self.registerFilters(smp, dapIndex)
            self.addDeviceInterface(smp)
            
    
    def setupBigLittle(self):
        '''Create big.LITTLE device using CTI synchronization'''
        
        ctiInfo = self.getCTIInfoForCores(coreNames_cortexA73 + coreNames_cortexA53)
        cores = [ DeviceCluster("big", self.cortexA73cores), DeviceCluster("LITTLE", self.cortexA53cores) ]
        bigLITTLE = CTISyncSMPDevice(self, "big.LITTLE", cores, ctiInfo, CTM_CHANNEL_SYNC_START, CTM_CHANNEL_SYNC_STOP)
        
        self.registerFilters(bigLITTLE, 0)
        self.addDeviceInterface(bigLITTLE)
    
    def setETFTraceEnabled(self, etfTrace, enabled):
        '''Enable/disable ETF trace capture'''
        if enabled:
            # Put the ETF in ETB mode
            etfTrace.getTMC().setMode(CSTMC.Mode.ETB)
        else:
            # Put the ETF in FIFO mode
            etfTrace.getTMC().setMode(CSTMC.Mode.ETF)
        
        self.enableCTIsForSink(etfTrace, enabled)
    
    def setETRTraceEnabled(self, etr, enabled):
        '''Enable/disable ETR trace capture'''
        if enabled:
            # Ensure TPIU is disabled
            self.TPIU.setEnabled(False)
        self.enableCTIsForSink(etr, enabled)
    
    def setDSTREAMTraceEnabled(self, enabled):
        '''Enable/disable DSTREAM trace capture'''
        self.TPIU.setEnabled(enabled)
        self.enableCTIsForSink(self.DSTREAM, enabled)

    def registerTraceSources_A53(self, traceCapture):
        '''Register all trace sources with trace capture device'''
        for i in range(len(coreNames_cortexA53)):
            core = self.getDeviceInterface(coreNames_cortexA53[i])
            coreTM = self.getTMForCore(core)
            if coreTM is not None and coreTM.isEnabled():
                self.registerCoreTraceSource(traceCapture, core, coreTM)
        
        i=len(coreNames_cortexA53)
        for macrocell in range(i, len(macrocellNames_cortexA53)):
            TM = self.getDeviceInterface(macrocellNames_cortexA53[macrocell])
            if TM is not None:
                #self.registerTraceSource(traceCapture, TM)
                pass
        
    def registerTraceSources_A73(self, traceCapture):
        '''Register all Cortex-A73 cluster trace sources with trace capture device'''
        for i in range(len(coreNames_cortexA73)):
            core = self.getDeviceInterface(coreNames_cortexA73[i])
            coreTM = self.getTMForCore(core)
            if coreTM is not None and coreTM.isEnabled():
                self.registerCoreTraceSource(traceCapture, core, coreTM)
        
        i=len(coreNames_cortexA73)
        for macrocell in range(i, len(macrocellNames_cortexA73)):
            TM = self.getDeviceInterface(macrocellNames_cortexA73[macrocell])
            if TM is not None:
                pass
                #self.registerTraceSource(traceCapture, TM)
        
    def registerTraceSources(self, traceCapture):
        '''Register all trace sources with trace capture device'''
        self.registerTraceSources_A53(traceCapture)
        self.registerTraceSources_A73(traceCapture)
        if self.STM0.isEnabled():
            self.registerTraceSource(traceCapture, self.STM0)	

    def registerCoreTraceSource(self, traceCapture, core, source):
        '''Register a trace source with trace capture device and enable triggers'''
        # Register with trace capture, associating with core
        traceCapture.addTraceSource(source, core.getID())
        
        # Source is managed by the configuration
        self.addManagedTraceDevices(traceCapture.getName(), [ source ])
        
        # CTI (if present) is also managed by the configuration
        cti, input, channel = self.getCTIForSource(source)
        if cti:
            self.addManagedTraceDevices(traceCapture.getName(), [ cti ])
    
    # +--------------------------------+
    # | Callback functions for options |
    # +--------------------------------+
    
    def optionValuesChanged(self):
        '''Callback to update the configuration state after options are changed'''
        if not self.isConnected():
            try:
                self.setInitialOptions()
            except:
                pass
        self.updateDynamicOptions()
        
    def setInitialOptions(self):
        '''Set the initial options'''
        traceMode_A53 = self.getOptionValue("options.Cortex-A53_SMP_0.traceCapture")
        traceMode_A73 = self.getOptionValue("options.Cortex-A73_SMP_0.traceCapture")    
        
        # Only manage cluster funnels and ETFs if we need them
        traceDevices = []

        coreTraceEnabled = self.getOptionValue("options.Cortex-A53_SMP_0.coreTrace")
        a53_0_enabled = False
        for core in range(len(clusterCores[0])):
            thisCoreTraceEnabled = self.getOptionValue("options.Cortex-A53_SMP_0.coreTrace.Cortex-A53_SMP_0_%d" % core)
            enableSource = coreTraceEnabled and thisCoreTraceEnabled
            coreTM = self.getTMForCore(self.getDeviceInterface(clusterCores[0][core]))
            self.setTraceSourceEnabled(coreTM, enableSource)
            self.setInternalTraceRange(coreTM, "Cortex-A53_SMP_0")
            self.setTimestampingEnabled(coreTM, self.getOptionValue("options.Cortex-A53_SMP_0.coreTrace.timestamp"))
            self.setContextIDEnabled(coreTM,
                                     self.getOptionValue("options.Cortex-A53_SMP_0.coreTrace.contextIDs"),
                                     "32")
            if enableSource:
                a53_0_enabled = True  			
        
        coreTraceEnabled = self.getOptionValue("options.Cortex-A73_SMP_0.coreTrace")
        a73_0_enabled = False
        for core in range(len(clusterCores[1])):
            thisCoreTraceEnabled = self.getOptionValue("options.Cortex-A73_SMP_0.coreTrace.Cortex-A73_SMP_0_%d" % core)
            enableSource = coreTraceEnabled and thisCoreTraceEnabled
            coreTM = self.getTMForCore(self.getDeviceInterface(clusterCores[1][core]))
            self.setTraceSourceEnabled(coreTM, enableSource)
            self.setInternalTraceRange(coreTM, "Cortex-A73_SMP_0")
            self.setTimestampingEnabled(coreTM, self.getOptionValue("options.Cortex-A73_SMP_0.coreTrace.timestamp"))
            self.setContextIDEnabled(coreTM,
                                     self.getOptionValue("options.Cortex-A73_SMP_0.coreTrace.contextIDs"),
                                     "32")
            if enableSource:
                a73_0_enabled = True   
        
        portWidthOpt = self.getOptions().getOption("options.trace.offChip.tpiuPortWidth")
        if portWidthOpt:
            portWidth = self.getOptionValue("options.trace.offChip.tpiuPortWidth")
            self.setPortWidth(int(portWidth))
        
        traceBufferOpt = self.getOptions().getOption("options.trace.offChip.traceBufferSize")
        if traceBufferOpt:
            traceBufferSize = self.getOptionValue("options.trace.offChip.traceBufferSize")
            self.setTraceBufferSize(traceBufferSize)
        
        stmEnabled = self.getOptionValue("options.stm.CSSTM")
        self.setTraceSourceEnabled(self.STM0, stmEnabled)
        
        if a53_0_enabled and not a73_0_enabled:
            traceDevices.append(self.Funnel1)
            traceDevices.append(self.ETF1)
        if a73_0_enabled and not a53_0_enabled:
            traceDevices.append(self.Funnel2)
            traceDevices.append(self.ETF2)
        if a73_0_enabled and a53_0_enabled and traceMode_A53 == "CSTMC_0":
            traceDevices.append(self.Funnel1)
            traceDevices.append(self.ETF1)
            traceDevices.append(self.Funnel2)
        if a73_0_enabled and a53_0_enabled and traceMode_A73 == "CSTMC_0":
            traceDevices.append(self.Funnel1)
            traceDevices.append(self.Funnel2)
            traceDevices.append(self.ETF2)
        if a73_0_enabled and a53_0_enabled and traceMode_A53 == "CSTMC_1":
            traceDevices.append(self.Funnel1)
            traceDevices.append(self.ETF1)
            traceDevices.append(self.Funnel2)
        if a73_0_enabled and a53_0_enabled and traceMode_A73 == "CSTMC_1":
            traceDevices.append(self.Funnel1)
            traceDevices.append(self.Funnel2)
            traceDevices.append(self.ETF2)

        # Now we know which trace sources are active and which funnels/ETFs we need
        # We can set up the managed device lists            
        self.setupETFTrace(traceDevices)
        self.setupETRTrace(traceDevices)
        self.setupDSTREAMTrace(traceDevices)
		
        # Handle trace capture options
        masterETFEnable = False
        ETREnable = False
        TPIUEnable = False

        if traceMode_A53 == "none":
            self.setETFTraceEnabled(self.ETF1Trace, False)
        elif traceMode_A53 == "CSTMC_2":
            self.setETFTraceEnabled(self.ETF1Trace, True)
        elif traceMode_A53 == "CSTMC_1":
            self.Funnel0.setPortEnabled(0)
            self.setETFTraceEnabled(self.ETF1Trace, False)
            masterETFEnable = True
        elif traceMode_A53 == "CSTMC_0":
            self.Funnel0.setPortEnabled(0)
            self.setETFTraceEnabled(self.ETF1Trace, False)
            ETREnable = True
        elif traceMode_A53 == "DSTREAM":
            self.Funnel0.setPortEnabled(0)
            self.setETFTraceEnabled(self.ETF1Trace, False)
            TPIUEnable = True

        if traceMode_A73 == "none":
            self.setETFTraceEnabled(self.ETF2Trace, False)
        elif traceMode_A73 == "CSTMC_3":
            self.setETFTraceEnabled(self.ETF2Trace, True)
        elif traceMode_A73 == "CSTMC_1":
            self.Funnel0.setPortEnabled(0)
            self.setETFTraceEnabled(self.ETF2Trace, False)
            masterETFEnable = True
        elif traceMode_A73 == "CSTMC_0":
            self.Funnel0.setPortEnabled(0)
            self.setETFTraceEnabled(self.ETF2Trace, False)
            ETREnable = True
        elif traceMode_A73 == "DSTREAM":
            self.Funnel0.setPortEnabled(0)
            self.setETFTraceEnabled(self.ETF2Trace, False)
            TPIUEnable = True

        self.setETFTraceEnabled(self.ETF0Trace, masterETFEnable)
        self.setETRTraceEnabled(self.ETR0, ETREnable)
        self.setDSTREAMTraceEnabled(TPIUEnable)	

        # Register trace sources for each trace sink
        # Global ETF
        self.registerTraceSources(self.ETF0Trace)
        # A53 cluster ETF
        self.registerTraceSources_A53(self.ETF1Trace)
        # A73 cluster ETF
        self.registerTraceSources_A73(self.ETF2Trace)
        self.registerTraceSources(self.ETR0)
        self.registerTraceSources(self.DSTREAM)
		
        managedDevs = self.getManagedDevices(traceMode_A53)	
        managedDevs1 = self.getManagedDevices(traceMode_A73)		
        merged_device = self.getManagedDevices_merge(managedDevs, managedDevs1)
		
        self.setManagedDeviceList(merged_device)

    def getManagedDevices_merge(self, list_1, list_2):
        '''Get the required set of managed devices for this configuration'''
        deviceList=list_1
		
        for d in list_2:
            if d not in deviceList:
                deviceList.append(d)
        
        return deviceList

    def getTraceCaptureForSource(self, source):
        if source in self.macrocells["cortexA53"]:
            return self.getTraceCaptureFromOption("options.Cortex-A53_SMP_0.traceCapture")
 
        if source in self.macrocells["cortexA73"]:
            return self.getTraceCaptureFromOption("options.Cortex-A73_SMP_0.traceCapture")
 
        return None
        
    def updateDynamicOptions(self):
        '''Update the dynamic options'''
        
        # Set up the ETR 0 buffer
        configureETRBuffer = self.getOptionValue("options.ETR.etrBuffer0")
        if configureETRBuffer:
            scatterGatherMode = self.getOptionValue("options.ETR.etrBuffer0.scatterGather")
            bufferStart = self.getOptionValue("options.ETR.etrBuffer0.start")
            bufferSize = self.getOptionValue("options.ETR.etrBuffer0.size")
            self.ETR0.setBaseAddress(bufferStart)
            self.ETR0.setTraceBufferSize(bufferSize)
            self.ETR0.setScatterGatherModeEnabled(scatterGatherMode)
            
        for core in range(len(self.cortexA53cores)):
            a53_rams.applyCacheDebug(configuration = self,
                                     optionName = "options.rams.cacheDebug",
                                     device = self.cortexA53cores[core])
            a53_rams.applyCachePreservation(configuration = self,
                                            optionName = "options.rams.cachePreserve",
                                            device = self.cortexA53cores[core])
        
        for core in range(len(self.cortexA73cores)):
            a73_rams.applyCacheDebug(configuration = self,
                                     optionName = "options.rams.cacheDebug",
                                     device = self.cortexA73cores[core])
        
    def getManagedDevices(self, traceKey):
        '''Get the required set of managed devices for this configuration'''
        deviceList = self.mgdPlatformDevs[:]
        for d in self.mgdTraceDevs.get(traceKey, []):
            if d not in deviceList:
                deviceList.append(d)
        
        return deviceList
    
    @staticmethod
    def getTraceMacrocellsForCoreType(coreType):
        '''Get the Trace Macrocells for a given coreType
           Use parameter-binding to ensure that the correct Macrocells
           are returned for the core type passed only'''
        def getMacrocells(self):
            return self.macrocells[coreType]
        return getMacrocells
    
    @staticmethod
    def getTraceMacrocellsForCluster(cluster):
        '''Get the Trace Macrocells for a given coreType
           Use parameter-binding to ensure that the correct Macrocells
           are returned for the core type and cluster passed only'''
        def getMacrocellsForCluster(self):
            return self.macrocells[cluster]
        return getMacrocellsForCluster
    
    # +------------------------------+
    # | Target independent functions |
    # +------------------------------+
    
    def registerTraceSource(self, traceCapture, source):
        '''Register trace source with trace capture device'''
        traceCapture.addTraceSource(source)
        self.addManagedTraceDevices(traceCapture.getName(), [ source ])
    
    def addManagedTraceDevices(self, traceKey, devs):
        '''Add devices to the set of devices managed by the configuration for this trace mode'''
        traceDevs = self.mgdTraceDevs.get(traceKey)
        if not traceDevs:
            traceDevs = []
            self.mgdTraceDevs[traceKey] = traceDevs
        for d in devs:
            if d not in traceDevs:
                traceDevs.append(d)
    
    def getTMForCore(self, core):
        '''Get trace macrocell for core'''
        coreName = core.getName()
        for i in range(len(coreNames)):
            if coreName == coreNames[i]:
                return self.getDeviceInterface(macrocellNames[i])
        
        return None
    
    def setInternalTraceRange(self, coreTM, coreName):
        
        traceRangeEnable = self.getOptionValue("options.%s.coreTrace.traceRange" % coreName)
        traceRangeStart = self.getOptionValue("options.%s.coreTrace.traceRange.start" % coreName)
        traceRangeEnd = self.getOptionValue("options.%s.coreTrace.traceRange.end" % coreName)
        
        if coreTM in self.traceRangeIDs:
            coreTM.clearTraceRange(self.traceRangeIDs[coreTM])
            del self.traceRangeIDs[coreTM]
        
        if traceRangeEnable:
            self.traceRangeIDs[coreTM] = coreTM.addTraceRange(traceRangeStart, traceRangeEnd)
    
    def createDSTREAM(self):
        self.DSTREAM = DSTREAMTraceCapture(self, "DSTREAM")
    
    def enableCTIsForSource(self, source, enabled):
        '''Enable/disable triggers using CTI associated with source'''
        cti, input, channel = self.getCTIForSource(source)
        if cti:
            self.enableCTIInput(cti, input, channel, enabled)
    
    def enableCTIInput(self, cti, input, channel, enabled):
        '''Enable/disable cross triggering between an input and a channel'''
        if enabled:
            cti.enableInputEvent(input, channel)
        else:
            cti.disableInputEvent(input, channel)
    
    def enableCTIsForSink(self, sink, enabled):
        '''Enable/disable triggers using CTI associated with source'''
        cti, output, channel = self.getCTIForSink(sink)
        if cti:
            self.enableCTIOutput(cti, output, channel, enabled)
    
    def enableCTIOutput(self, cti, output, channel, enabled):
        '''Enable/disable cross triggering between a channel and an output'''
        if enabled:
            cti.enableOutputEvent(output, channel)
        else:
            cti.disableOutputEvent(output, channel)
    
    def getMacrocellNameForCore(self, coreName):
        '''Get the index of the dap with which this core is associated'''
        for index in range(len(coreNames)):
            if coreNames[index] == coreName:
                return macrocellNames[index]
        return None
    
    def addMacrocellsToClusterList(self, coreName, tm):
        '''Add the macrocell to the cluster map'''
        for i in range(len(clusterNames)):
            clusterCoreNames = clusterCores[i];
            if coreName in clusterCoreNames:
                self.macrocells[clusterNames[i]].append(tm)
    
    def createFunnel(self, funnelDev, name):
        funnel = CSFunnel(self, self.findDevice(funnelDev), name)
        funnel.setAllPortsDisabled() # Will enable for each source later
        return funnel
    
    def setFunnelPortEnabled(self, funnelName, port, enabled):
        '''Enable/disable a funnel port'''
        funnel = self.getDeviceInterface(funnelName)
        if funnel:
            if enabled:
                funnel.setPortEnabled(port)
            else:
                funnel.setPortDisabled(port)
    
    def createSTM(self, stmDev, streamID, name):
        stm = STMTraceSource(self, self.findDevice(stmDev), streamID, name)
        # Disabled by default - will enable with option
        stm.setEnabled(False)
        return stm
    
    def getDapIndex(self, coreName):
        '''Get the index of the dap with which this core is associated'''
        for index in range(len(coreNames)):
            if coreNames[index] == coreName:
                return dapIndices[index]
        return 0
    
    def getDevicesFromNameList(self, devNames):
        devs = []
        for devName in devNames:
            dev = self.getDeviceInterface(devName)
            if not dev is None:
                devs.append(dev)
        
        return devs
    
    def getCTIInfoForCores(self, cores):
        '''Get the CTI info for the given cores - return a map of CTI info against core'''
        ctiInfo = {}
        for coreName in cores:
            for i in range(len(coreNames)):
                if coreName == coreNames[i] and ctiNames[i] is not None:
                    ctiInfoForDevice =  CTISyncSMPDevice.DeviceCTIInfo(self.getDeviceInterface(ctiNames[i]), CTISyncSMPDevice.DeviceCTIInfo.NONE, ctiCoreTriggers[i], 0, 0)
                    core = self.getDeviceInterface(coreName)
                    ctiInfo[core] = ctiInfoForDevice
        
        return ctiInfo
    
    def postConnect(self):
        DTSLv1.postConnect(self)
        
        try:
            freq = self.getOptionValue("options.trace.traceOpts.timestampFrequency")
        except:
            return
        
        # Update the value so the trace decoder can access it
        tsInfo = TimestampInfo(freq)
        self.setTimestampInfo(tsInfo)
    
    def setTimestampingEnabled(self, xtm, state):
        xtm.setTimestampingEnabled(state)
    
    def setContextIDEnabled(self, xtm, state, size):
        if state == False:
            xtm.setContextIDs(False, IARMCoreTraceSource.ContextIDSize.NONE)
        else:
            contextIDSizeMap = {
                "8":IARMCoreTraceSource.ContextIDSize.BITS_7_0,
                "16":IARMCoreTraceSource.ContextIDSize.BITS_15_0,
                "32":IARMCoreTraceSource.ContextIDSize.BITS_31_0 }
            xtm.setContextIDs(True, contextIDSizeMap[size])
    
class DtslScript_DSTREAM_ST(DtslScript):
    @staticmethod
    def getOptionList():
        return [
            DTSLv1.tabSet("options", "Options", childOptions=
                [DTSLv1.tabPage("Cortex-A53_SMP_0", "Cortex-A53", childOptions=[
                    DTSLv1.enumOption('traceCapture', 'Trace capture method', defaultValue="none",
                        values = [("none", "None"), ("CSTMC_0", "System Memory Trace Buffer (CSTMC_0/ETR)"), ("CSTMC_1", "On Chip Trace Buffer (CSTMC_1/ETF_Global)"), ("CSTMC_2", "On Chip Trace Buffer (CSTMC_2/ETF_A53)"), ("DSTREAM", "streaming trace")]),
                    DTSLv1.infoElement("traceOpts", "Trace Options", childOptions=[
                        DTSLv1.integerOption('timestampFrequency', 'Timestamp frequency', defaultValue=25000000, isDynamic=False, description="This value will be used to set the Counter Base Frequency ID Register of the Timestamp generator.\nIt represents the number of ticks per second and is used to translate the timestamp value reported into a number of seconds.\nNote that changing this value may not result in a change in the observed frequency."),
                    ]),
                    DTSLv1.infoElement("offChip", "Off-Chip Trace", childOptions=[
                        DTSLv1.enumOption('tpiuPortWidth', 'TPIU Port Width', defaultValue="16",
                            values = [("1", "1 bit"), ("2", "2 bit"), ("3", "3 bit"), ("4", "4 bit"), ("5", "5 bit"), ("6", "6 bit"), ("7", "7 bit"), ("8", "8 bit"), ("9", "9 bit"), ("10", "10 bit"), ("11", "11 bit"), ("12", "12 bit"), ("13", "13 bit"), ("14", "14 bit"), ("15", "15 bit"), ("16", "16 bit")], isDynamic=False),
                    ]),                    
                    DTSLv1.booleanOption('coreTrace', 'Enable Cortex-A53 core trace', defaultValue=False,
                        childOptions =
                            # Allow each source to be enabled/disabled individually
                            [ DTSLv1.booleanOption('Cortex-A53_SMP_0_%d' % core, "Enable " + clusterCores[0][core] + " trace", defaultValue=True)
                            for core in range(len(clusterCores[0])) ] +
                            [ DTSLv1.booleanOption('timestamp', "Enable ETM Timestamps", description="Controls the output of timestamps into the ETM output streams", defaultValue=True) ] +
                            [ DTSLv1.booleanOption('contextIDs', "Enable ETM Context IDs", description="Controls the output of context ID values into the ETM output streams", defaultValue=True)
                            ] +
                            [ ETMv4TraceSource.cycleAccurateOption(DtslScript.getTraceMacrocellsForCluster("Cortex-A53_SMP_0"))] +
                            [ # Trace range selection (e.g. for linux kernel)
                            DTSLv1.booleanOption('traceRange', 'Trace capture range',
                                description=TRACE_RANGE_DESCRIPTION,
                                defaultValue = False,
                                childOptions = [
                                    DTSLv1.integerOption('start', 'Start address',
                                        description='Start address for trace capture',
                                        defaultValue=0,
                                        display=IIntegerOption.DisplayFormat.HEX),
                                    DTSLv1.integerOption('end', 'End address',
                                        description='End address for trace capture',
                                        defaultValue=0xFFFFFFFF,
                                        display=IIntegerOption.DisplayFormat.HEX)
                                ])
                            ]
                        ),
                ])]
                +[DTSLv1.tabPage("Cortex-A73_SMP_0", "Cortex-A73", childOptions=[
                    DTSLv1.enumOption('traceCapture', 'Trace capture method', defaultValue="none",
                        values = [("none", "None"), ("CSTMC_0", "System Memory Trace Buffer (CSTMC_0/ETR)"), ("CSTMC_1", "On Chip Trace Buffer (CSTMC_1/ETF_Global)"), ("CSTMC_3", "On Chip Trace Buffer (CSTMC_3/ETF_A73)"), ("DSTREAM", "streaming trace")]),
                    DTSLv1.infoElement("traceOpts", "Trace Options", childOptions=[
                        DTSLv1.integerOption('timestampFrequency', 'Timestamp frequency', defaultValue=25000000, isDynamic=False, description="This value will be used to set the Counter Base Frequency ID Register of the Timestamp generator.\nIt represents the number of ticks per second and is used to translate the timestamp value reported into a number of seconds.\nNote that changing this value may not result in a change in the observed frequency."),
                    ]),
                    DTSLv1.infoElement("offChip", "Off-Chip Trace", childOptions=[
                        DTSLv1.enumOption('tpiuPortWidth', 'TPIU Port Width', defaultValue="16",
                            values = [("1", "1 bit"), ("2", "2 bit"), ("3", "3 bit"), ("4", "4 bit"), ("5", "5 bit"), ("6", "6 bit"), ("7", "7 bit"), ("8", "8 bit"), ("9", "9 bit"), ("10", "10 bit"), ("11", "11 bit"), ("12", "12 bit"), ("13", "13 bit"), ("14", "14 bit"), ("15", "15 bit"), ("16", "16 bit")], isDynamic=False),
                    ]), 
                    DTSLv1.booleanOption('coreTrace', 'Enable Cortex-A73 core trace', defaultValue=False,
                        childOptions =
                            # Allow each source to be enabled/disabled individually
                            [ DTSLv1.booleanOption('Cortex-A73_SMP_0_%d' % core, "Enable " + clusterCores[1][core] + " trace", defaultValue=True)
                            for core in range(len(clusterCores[1])) ] +
                            [ DTSLv1.booleanOption('timestamp', "Enable ETM Timestamps", description="Controls the output of timestamps into the ETM output streams", defaultValue=True) ] +
                            [ DTSLv1.booleanOption('contextIDs', "Enable ETM Context IDs", description="Controls the output of context ID values into the ETM output streams", defaultValue=True)
                            ] +
                            [ ETMv4TraceSource.cycleAccurateOption(DtslScript.getTraceMacrocellsForCluster("Cortex-A73_SMP_0"))] +
                            [ # Trace range selection (e.g. for linux kernel)
                            DTSLv1.booleanOption('traceRange', 'Trace capture range',
                                description=TRACE_RANGE_DESCRIPTION,
                                defaultValue = False,
                                childOptions = [
                                    DTSLv1.integerOption('start', 'Start address',
                                        description='Start address for trace capture',
                                        defaultValue=0,
                                        display=IIntegerOption.DisplayFormat.HEX),
                                    DTSLv1.integerOption('end', 'End address',
                                        description='End address for trace capture',
                                        defaultValue=0xFFFFFFFF,
                                        display=IIntegerOption.DisplayFormat.HEX)
                                ])
                            ]
                        ),
                ])]
                +[DTSLv1.tabPage("ETR", "ETR", childOptions=[
                    DTSLv1.booleanOption('etrBuffer0', 'Configure the system memory trace buffer to be used by the CSTMC_0/ETR device', defaultValue=False,
                        childOptions = [
                            DTSLv1.integerOption('start', 'Start address',
                            description='Start address of the system memory trace buffer to be used by the CSTMC_0/ETR device',
                            defaultValue=0x00100000,
                            display=IIntegerOption.DisplayFormat.HEX),
                            DTSLv1.integerOption('size', 'Size in bytes',
                            description='Size of the system memory trace buffer in bytes',
                            defaultValue=0x8000,
                            isDynamic=True,
                            display=IIntegerOption.DisplayFormat.HEX),
                            DTSLv1.booleanOption('scatterGather', 'Enable scatter-gather mode',
                            defaultValue=False,
                            description='When enabling scatter-gather mode, the start address of the on-chip trace buffer must point to a configured scatter-gather table')
                        ]
                    ),
                ])]
                +[DTSLv1.tabPage("stm", "STM", childOptions=[
                    DTSLv1.booleanOption('CSSTM', 'Enable CSSTM trace', defaultValue=False),
                ])]
                +[DTSLv1.tabPage("rams", "Cache RAMs", childOptions=[
                    # Turn cache debug mode on/off
                    DTSLv1.booleanOption('cacheDebug', 'Cache debug mode',
                                         description='Turning cache debug mode on enables reading the cache RAMs. Enabling it may adversely impact debug performance.',
                                         defaultValue=False, isDynamic=True),
                    DTSLv1.booleanOption('cachePreserve', 'Preserve cache contents in debug state',
                                         description='Preserve the contents of caches while the core is stopped.',
                                         defaultValue=False, isDynamic=True),
                ])]
            )
        ]

    # +--------------------------------+
    # | Callback functions for options |
    # +--------------------------------+
    
    def optionValuesChanged(self):
        '''Callback to update the configuration state after options are changed'''
        if not self.isConnected():
            try:
                DtslScript.setInitialOptions(self)
            except:
                pass
        DtslScript.updateDynamicOptions(self)

    def createDSTREAM(self):
        self.DSTREAM = DSTREAMSTStoredTraceCapture(self, "DSTREAM")

    def setupDSTREAMTrace(self, devices):
        '''Setup DSTREAM trace capture'''
        
        # configure the TPIU for continuous mode
        self.TPIU.setFormatterMode(FormatterMode.CONTINUOUS)
        
        # register other trace components
        self.DSTREAM.setTraceComponentOrder([ self.ETF0, self.Funnel0, self.TPIU ] + devices )
        
        # register the DSTREAM with the configuration
        self.addTraceCaptureInterface(self.DSTREAM)
        
        # automatically handle connection/disconnection to trace components
        self.addManagedTraceDevices("DSTREAM", [ self.Funnel0, self.TPIU, self.ETF0, self.DSTREAM ] + devices )		
    
    def setTraceBufferSize(self, mode):
        '''Configuration option setter method for the trace buffer size'''
        bufferSize = 64*1024*1024
        if (mode == "64MB"):
            bufferSize = 64*1024*1024
        if (mode == "128MB"):
            bufferSize = 128*1024*1024
        if (mode == "256MB"):
            bufferSize = 256*1024*1024
        if (mode == "512MB"):
            bufferSize = 512*1024*1024
        if (mode == "1GB"):
            bufferSize = 1*1024*1024*1024
        if (mode == "2GB"):
            bufferSize = 2*1024*1024*1024
        if (mode == "4GB"):
            bufferSize = 4*1024*1024*1024
        if (mode == "8GB"):
            bufferSize = 8*1024*1024*1024
        if (mode == "16GB"):
            bufferSize = 16*1024*1024*1024
        if (mode == "32GB"):
            bufferSize = 32*1024*1024*1024
        if (mode == "64GB"):
            bufferSize = 64*1024*1024*1024
        if (mode == "128GB"):
            bufferSize = 128*1024*1024*1024
        
        self.DSTREAM.setMaxCaptureSize(bufferSize)
    

