| /* --COPYRIGHT--,ESD |
| * Copyright (c) 2008-2019 Texas Instruments Incorporated |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v1.0 and Eclipse Distribution License |
| * v. 1.0 which accompanies this distribution. The Eclipse Public License is |
| * available at http://www.eclipse.org/legal/epl-v10.html and the Eclipse |
| * Distribution License is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * Contributors: |
| * Texas Instruments - initial implementation |
| * --/COPYRIGHT--*/ |
| |
| /* |
| * 'CATEGORIES' is an array of the string names of all of the diags bits. |
| * This array is initialized by the initCategories function, which should |
| * be called before referencing this global variable. |
| * 'init' is used to track whether CATEGORIES has been initialized already. |
| */ |
| var CATEGORIES; |
| var init; |
| |
| /* |
| * ======== needsDiagsMask ======== |
| * Returns non-zero if module needs a runtime mask |
| */ |
| function needsDiagsMask(mod) |
| { |
| /* The XOR clause only verifies if there are bits that could be ON at the |
| * runtime (diagsIncluded), but are not ALWAYS_ON (diagsEnabled), which |
| * means they are RUNTIME_ON or RUNTIME_OFF (the 1^0 case). |
| * The 0^1 case, in which a bit can't be ON, but is ALWAYS_ON is not |
| * possible. The cases 0^0 and 1^1 don't require a mask at the runtime. |
| */ |
| return (mod.Module__diagsIncluded ^ mod.Module__diagsEnabled); |
| } |
| |
| /* |
| * ======== initCategories ======== |
| */ |
| function initCategories() |
| { |
| if (init == null) { |
| init = true; |
| CATEGORIES = []; |
| var Types = xdc.module("xdc.runtime.Types"); |
| for (var name in Types.common$) { |
| if (name.substring(0, 6) == "diags_") { |
| CATEGORIES.push(name.substring(6)); |
| } |
| } |
| } |
| } |
| |
| /* |
| * ======== module$use ======== |
| */ |
| function module$use() |
| { |
| xdc.useModule("xdc.runtime.Registry"); |
| |
| /* If Diags is used, Logs or Asserts might be required, but we would have |
| * to go through all bits to figure out which of these modules are |
| * needed. It's easier just to include them both because an app that |
| * includes Diags is not being built for minimal footprint, and the linker |
| * will eliminate whatever was not needed. |
| */ |
| xdc.useModule("xdc.runtime.Log"); |
| xdc.useModule("xdc.runtime.Assert"); |
| } |
| |
| /* |
| * ======== module$static$init ======== |
| */ |
| function module$static$init(obj, params) |
| { |
| initCategories(); |
| |
| for each (var mod in Program.targetModules()) { |
| |
| if (mod.PROXY$) { |
| continue; |
| } |
| |
| var dincl = 0; /* bits that could be ON at runtime */ |
| var denab = 0; /* bits initially ON, and can't be turned off */ |
| var dmask = 0; /* bits that are ON initially */ |
| |
| for each (var dc in CATEGORIES) { |
| |
| /* |
| * Deprecate USER7 and USER8 and warn the user appropriately. |
| * This API will ensure that INFO == USER7 and ANALYSIS == |
| * USER8 so that we don't have conflicting values. |
| */ |
| deprecateUser7And8(this, mod, dc); |
| |
| switch (mod.common$['diags_' + dc]) { |
| case this.ALWAYS_OFF: |
| break; |
| case this.ALWAYS_ON: |
| dincl |= this[dc]; |
| denab |= this[dc]; |
| break; |
| case this.RUNTIME_OFF: |
| dincl |= this[dc]; |
| this.setMaskEnabled = true; |
| break; |
| case this.RUNTIME_ON: |
| dincl |= this[dc]; |
| dmask |= this[dc]; |
| this.setMaskEnabled = true; |
| break; |
| } |
| mod.common$.$seal('diags_' + dc); |
| } |
| |
| mod.$unseal('Module__diagsEnabled'); |
| mod.$unseal('Module__diagsIncluded'); |
| mod.$unseal('Module__diagsMask'); |
| mod.Module__diagsEnabled = denab; |
| mod.Module__diagsIncluded = dincl; |
| |
| mod.$$bind('$$diagsMask', dmask); |
| mod.Module__diagsMask = needsDiagsMask(mod) |
| ? $externPtr(mod.$name.replace(/\./g, '_') |
| + '_Module__root__V.mask') |
| : null; |
| |
| mod.$seal('Module__diagsEnabled'); |
| mod.$seal('Module__diagsIncluded'); |
| mod.$seal('Module__diagsMask'); |
| } |
| |
| /* if the Diags_setmask() function is enabled, reference a table of |
| * name:value pairs generated by Dict.xdt that allows Diags_setMask() |
| * to look up module masks by the module's name. |
| */ |
| if (this.setMaskEnabled) { |
| if (this.$package.Text.isLoaded) { |
| this.dictBase = '&xdc_runtime_Diags_dictElems[0]'; |
| } |
| else { |
| /* The part of setMask() that deals with RTSC modules needs the |
| * strings on the target. |
| */ |
| this.setMaskEnabled = false; |
| } |
| } |
| } |
| |
| /* |
| * ======== deprecateUser7And8 ======== |
| * This function is used to deprecate the use of the USER7 and USER8 bits. |
| * It warns the user if they modify USER7 or USER8 from their default value |
| * of ALWAYS_OFF. If USER7 or USER8 have been modified, any value in INFO or |
| * ANALYSIS is given priority unless those bits have not been modified. |
| * |
| * In all cases, this function will ultimately make sure that USER7 and INFO |
| * have the same value and that USER8 and ANALYSIS have the same value. If it |
| * makes any changes which the user might not be expecting, a warning is |
| * issued. |
| * |
| * When to remove: This code can be removed once 7 and 8 have been deprecated |
| * long enough and we decide to simply remove Diags.USER7 and Diags.USER8 |
| * completely and essentially break compatibility with configurations that |
| * modify those bits. |
| */ |
| function deprecateUser7And8(diagsMod, mod, dc) |
| { |
| if (dc == 'USER7' && mod.common$.diags_USER7 != mod.common$.diags_INFO) { |
| /* If the user has modified USER7 independently of INFO */ |
| if (mod.common$.diags_USER7 != diagsMod.ALWAYS_OFF) { |
| var msg = mod.$name + ".common$.diags_USER7 has been modified " |
| + "from its default. Diags.USER7 has been deprecated " |
| + "and is now equivalent to Diags.INFO."; |
| |
| /* If INFO has been modified, give its value priority. */ |
| if (mod.common$.diags_INFO != diagsMod.ALWAYS_OFF) { |
| var msg2 = msg + " diags_INFO has also been changed from its " |
| + "default, so the value " |
| + String(mod.common$.diags_INFO) + " from INFO " |
| + "will be used."; |
| |
| diagsMod.$logWarning(msg2, mod, "diags_USER7"); |
| |
| /* Make USER7 equivalent to INFO */ |
| mod.common$.diags_USER7 = mod.common$.diags_INFO; |
| } |
| /* Otherwise, use the value in USER7 */ |
| else { |
| var msg2 = msg + " diags_INFO has not been changed from its " |
| + "default, so the value " |
| + String(mod.common$.diags_USER7) + " from USER7 " |
| + "will be used."; |
| |
| diagsMod.$logWarning(msg2, mod, "diags_USER7"); |
| |
| /* Make INFO equivalent to USER7 */ |
| mod.common$.diags_INFO = mod.common$.diags_USER7; |
| } |
| } |
| /* Otherwise, just quietly set USER7 equal to INFO */ |
| else { |
| mod.common$.diags_USER7 = mod.common$.diags_INFO; |
| } |
| } |
| else if (dc == 'USER8' |
| && mod.common$.diags_USER8 != mod.common$.diags_ANALYSIS) { |
| /* If the user has modified USER8 independently of ANALYSIS */ |
| if (mod.common$.diags_USER8 != diagsMod.ALWAYS_OFF) { |
| |
| var msg = mod.$name + ".common$.diags_USER8 has been modified " |
| + "from its default. Diags.USER8 has been deprecated " |
| + "and is now equivalent to Diags.ANALYSIS."; |
| |
| /* If ANALYSIS has also been modified, give its value priority. */ |
| if (mod.common$.diags_ANALYSIS != diagsMod.ALWAYS_OFF) { |
| var msg2 = msg + " diags_ANALYSIS has also been changed from " |
| + "its default, so the value " |
| + String(mod.common$.diags_ANALYSIS) |
| + " from ANALYSIS will be used."; |
| |
| diagsMod.$logWarning(msg2, mod, "diags_USER8"); |
| |
| /* Make USER8 equivalent to ANALYSIS */ |
| mod.common$.diags_USER8 = mod.common$.diags_ANALYSIS; |
| } |
| /* Otherwise, user the value in USER8 */ |
| else { |
| var msg2 = msg + " diags_ANALYSIS has not been changed from " |
| + "its default, so the value " |
| + String(mod.common$.diags_USER8) + " from USER8 " |
| + "will be used."; |
| |
| diagsMod.$logWarning(msg2, mod, "diags_USER8"); |
| |
| /* Make ANALYSIS equivalent to USER8 */ |
| mod.common$.diags_ANALYSIS = mod.common$.diags_USER8; |
| } |
| } |
| /* Otherwise, just quietly set USER8 equal to ANALYSIS */ |
| else { |
| mod.common$.diags_USER8 = mod.common$.diags_ANALYSIS; |
| } |
| } |
| } |
| |
| /* |
| * ======== setMaskMeta ======== |
| */ |
| function setMaskMeta(pat, mask, mode) |
| { |
| if (typeof pat == 'string') { |
| pat = '^' + pat.replace(/\./g, '\\.').replace(/%$/, '.*') + '$'; |
| } |
| |
| var re = RegExp(pat); |
| |
| initCategories(); |
| |
| /* For all modules... */ |
| for each (var mod in xdc.om.$modules) { |
| if (mod.$hostonly || !mod.$used || mod.PROXY$) { |
| continue; |
| } |
| /* If the module name matches the pattern... */ |
| if (mod.$name.match(re)) { |
| /* |
| * Set module's common$.diags_* properties based on the bits set |
| * in 'mask'. |
| */ |
| for each (var dc in CATEGORIES) { |
| if (mask & this[dc]) { |
| mod.common$['diags_' + dc] = mode; |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * ======== viewInitDiagsMasks ======== |
| * ROV view to display the state of the diags masks for all modules in the |
| * system. |
| * |
| * This view uses the generic TREE_TABLE view type. It displays the module and |
| * package heirarchy on the left, and displays the diags mask state for the |
| * selected module (or the modules in the selected package) on the right in a |
| * table. |
| */ |
| function viewInitDiagsMasks() |
| { |
| var Program = xdc.useModule('xdc.rov.Program'); |
| var Model = xdc.useModule('xdc.rov.Model'); |
| |
| /* Initialize the CATEGORIES array defined at the top of this file. */ |
| initCategoriesRov(); |
| |
| /* Retrieve the package heirarchy. */ |
| var modList = Model.getModuleList(); |
| |
| /* |
| * This will return a root TreeNode whose name is "Module List" and |
| * whose children are the top level packages e.g. 'xdc'. |
| */ |
| var masksView = getPackageMasksView(modList); |
| |
| return (masksView.children); |
| } |
| |
| /* |
| * ======== initCategoriesRov ======== |
| * Types.common$ does not exist at ROV time, so we just have to hard code |
| * the categories list. |
| */ |
| function initCategoriesRov() |
| { |
| if (init == null) { |
| init = true; |
| CATEGORIES = [ |
| "ASSERT", |
| "ENTRY", |
| "EXIT", |
| "INTERNAL", |
| "LIFECYCLE", |
| "STATUS", |
| "USER1", |
| "USER2", |
| "USER3", |
| "USER4", |
| "USER5", |
| "USER6", |
| "USER7", |
| "INFO", |
| "USER8", |
| "ANALYSIS" |
| ]; |
| } |
| } |
| |
| /* |
| * ======== getPackageMasksView ======== |
| * This recursive function returns an xdc.rov.Program.TreeNode representing |
| * the given package. |
| * |
| * The 'pkg' object is a package from the module list returned by |
| * Model.getModuleList(). |
| */ |
| function getPackageMasksView(pkg) |
| { |
| var Diags = xdc.useModule('xdc.runtime.Diags'); |
| var Program = xdc.useModule('xdc.rov.Program'); |
| |
| /* Create a TreeNode to add to the view to represent this package. */ |
| var pkgNode = new Program.TreeNode(); |
| |
| /* Set the display name of the package node. */ |
| pkgNode.label = pkg.name; |
| |
| /* |
| * First, make recursive calls to get the TreeNode for each of the |
| * sub packages. |
| */ |
| pkgNode.children = new Array(); |
| for each (var subPkg in pkg.subPkgs) { |
| /* Make a recursive call to get the TreeNode for the sub package. */ |
| var subPkgView = getPackageMasksView(subPkg); |
| |
| /* Add the sub package to this package's view. */ |
| pkgNode.children[pkgNode.children.length++] = subPkgView; |
| } |
| |
| /* Get the diags mask for each of the modules. */ |
| pkgNode.properties = new Array(); |
| for each (var mod in pkg.modules) { |
| |
| /* Create a view structure for the module. */ |
| var maskView = Program.newViewStruct('xdc.runtime.Diags', 'DiagsMasks'); |
| |
| /* Set the module's name. */ |
| maskView.Module = mod.name; |
| |
| /* Get the module's configuration. */ |
| var modCfg = Program.getModuleConfig(mod.fullName); |
| |
| /* Set the module's logger. */ |
| if (modCfg.common$.logger == null) { |
| maskView.logger = "null"; |
| } |
| else if (modCfg.common$.logger.instance.name) { |
| maskView.logger = modCfg.common$.logger.instance.name; |
| } |
| else { |
| maskView.logger = String(modCfg.common$.logger.$name); |
| } |
| |
| /* The diags mask is located at the following symbol. */ |
| var diagsSym = mod.fullName.replace(/\./g, '_') |
| + '_Module__diagsMask__C'; |
| |
| /* Get the address of the diags mask. */ |
| var diagsSymAddr = Program.lookupSymbolValue(diagsSym); |
| |
| /* If the symbol does not exist... */ |
| if (diagsSymAddr == -1) { |
| /* |
| * There's no runtime mask, so just display the bits from the |
| * configuration. |
| */ |
| addConfigMaskView(pkgNode, maskView, mod); |
| |
| /* Continue to the next module. */ |
| continue; |
| } |
| |
| var ScalarStructs = xdc.useModule('xdc.rov.support.ScalarStructs'); |
| |
| /* |
| * The diagsMask__C symbol holds the address of a pointer to the |
| * actual diagsMask. Retrieving the diagsMask requires a double |
| * de-reference. |
| */ |
| var maskAddr; |
| try { |
| maskAddr = Program.fetchStruct(ScalarStructs.S_Ptr$fetchDesc, diagsSymAddr).elem; |
| } |
| catch (e) { |
| /* Display the error. */ |
| Program.displayError(maskView, 'Module', |
| "Caught an exception while fetching the " |
| + "address of the diags mask: " + e); |
| /* Add the view without the mask filled in */ |
| pkgNode.properties[pkgNode.properties.length++] = maskView; |
| } |
| |
| /* If the value at diagsMask__C is zero.. */ |
| if (maskAddr == 0) { |
| /* |
| * There's no runtime mask, so just display the bits from the |
| * configuration. |
| */ |
| addConfigMaskView(pkgNode, maskView, mod); |
| |
| /* Continue to the next module. */ |
| continue; |
| } |
| |
| /* |
| * Dereference the pointer at diagsMask__C to retrieve the actual |
| * diags mask. |
| */ |
| var mask; |
| try { |
| mask = |
| Program.fetchStruct(ScalarStructs.S_Bits16$fetchDesc, |
| maskAddr).elem; |
| } |
| catch (e) { |
| /* Display the error. */ |
| Program.displayError(maskView, 'Module', |
| "Caught an exception while fetching the " |
| + "diags mask: " + e); |
| /* Add the view without the mask filled in */ |
| pkgNode.properties[pkgNode.properties.length++] = maskView; |
| } |
| |
| /* Display the bit settings based on the runtime values in the mask. */ |
| addRuntimeMaskView(pkgNode, maskView, mod, mask); |
| } |
| |
| return (pkgNode); |
| } |
| |
| /* |
| * ======== addConfigMaskView ======== |
| * Get a module's diags mask setting from the configuration. |
| * This API is called when the module does not have a runtime mask, which |
| * happens when there is no logger configured or when all of the mask bits |
| * are set to ALWAYS_OFF or ALWAYS_ON. |
| */ |
| function addConfigMaskView(pkgNode, maskView, mod) |
| { |
| var Program = xdc.useModule('xdc.rov.Program'); |
| |
| /* Get the module's configuration. */ |
| var modCfg = Program.getModuleConfig(mod.fullName); |
| |
| /* Display the mask values from the configuration. */ |
| for each (var cat in CATEGORIES) { |
| var state = modCfg.common$["diags_" + cat]; |
| |
| // TODO - If we're displaying the mask only based on the configuration, |
| // yet one of the bits is runtime on/off, that should be an error? |
| |
| /* Remove the 'xdc.runtime.Diags' from the beginning of the string. */ |
| if (cat in maskView) { |
| maskView[cat] = state.substring(18, state.length); |
| } |
| } |
| |
| /* Add the view structure to the overall view. */ |
| pkgNode.properties[pkgNode.properties.length++] = maskView; |
| } |
| |
| /* |
| * ======== addRuntimeMaskView ======== |
| * Get a module's diags mask settings from the runtime mask. |
| * The diags mask only tells us on/off; it does not tell us whether the |
| * bit is ALWAYS or RUNTIME. For this info, we have to first retrieve the |
| * module's initial diags settings from the configuration. |
| */ |
| function addRuntimeMaskView(pkgNode, maskView, mod, mask) |
| { |
| var Program = xdc.useModule('xdc.rov.Program'); |
| var Diags = xdc.useModule('xdc.runtime.Diags'); |
| |
| /* Get the module's configuration. */ |
| var modCfg = Program.getModuleConfig(mod.fullName); |
| |
| for each (var cat in CATEGORIES) { |
| /* Skip over USER7 and USER8. */ |
| if (!(cat in maskView)) { |
| continue; |
| } |
| |
| /* Get the configured value of the bit. */ |
| var cfgVal = modCfg.common$["diags_" + cat]; |
| |
| /* |
| * Get the runtime status of the bit. This evaluates to true (ON) |
| * or false (OFF) |
| */ |
| var rtVal = (mask & Diags[cat]) != 0; |
| |
| /* If the bit was configured to ALWAYS_ON... */ |
| if (cfgVal == "xdc.runtime.Diags.ALWAYS_ON") { |
| /* |
| * The runtime mask value doesn't matter, and is not even |
| * guaranteed to be on. |
| */ |
| maskView[cat] = "ALWAYS_ON"; |
| } |
| /* If the bit was configured to ALWAYS_OFF... */ |
| else if (cfgVal == "xdc.runtime.Diags.ALWAYS_OFF") { |
| /* The runtime mask value doesn't matter. */ |
| maskView[cat] = "ALWAYS_OFF"; |
| } |
| /* Otherwise, it's a runtime bit, display it's runtime state. */ |
| else if (rtVal == true) { |
| maskView[cat] = "RUNTIME_ON"; |
| } |
| else { |
| maskView[cat] = "RUNTIME_OFF"; |
| } |
| } |
| |
| /* Add the view structure to the overall view. */ |
| pkgNode.properties[pkgNode.properties.length++] = maskView; |
| } |