blob: 06c45fae1879e389a0bdd10237760c8785701825 [file] [log] [blame]
/*
* ======== StateReader ========
* These APIs are all designed so that they will not re-read data that has already been read in.
*/
var symTable;
var strDec;
/*
* ======== instance$meta$init ========
*/
function instance$meta$init(inSymTable, inStrDec)
{
symTable = inSymTable;
strDec = inStrDec;
}
/*
* ======== fetchModuleState ========
* Scans the given module's module state structure. If the structure has
* already been scanned, this function returns immediately.
*/
function fetchModuleState(mod)
{
/* Return if the object has already been scanned. */
if (mod.state) {
return;
}
/* If the module does not have module state, return null. */
if (!('Module_State' in mod.useMod)) {
mod.state = null;
mod.addr = "N/A";
return;
}
/* Look up the Module state structure and fetch it. */
mod.addr = $addr(symTable.getSymbolValue(mod.name.replace(/\./g, '_') +
'_Module__state__V'));
var modState = strDec.fetchStruct(mod.useMod.Module_State,
Number(mod.addr), true);
/* Bind the state structure to the module as the state field */
mod.state = modState;
}
/*
* ======== fetchAllInstStates ========
* This function makes sure that all of the instance state structures for
* this module have been scanned in. It does not call any view$init functions.
*/
function fetchAllInstStates(mod)
{
/* Retrieves the addresses of all of the instance state structures. */
fetchAllInstAddrs(mod);
/* Fetch all of the static instance states. */
for (var i = 0; i < mod.staticInstAddrs.length; i++) {
fetchInstState(mod, mod.staticInstAddrs[i], i);
}
/* Fetch all of the dynamic instance states. */
for (var i = 0; i < mod.dynInstAddrs.length; i++) {
fetchInstState(mod, mod.dynInstAddrs[i], -1);
}
}
/*
* ======== fetchAllInstAddrs ========
* Retrieves the addresses of all of the statically and dynamically created
* instances. These will be placed in mod.staticInstAddrs and
* mod.dynInstAddrs.
*
* TODO - fetchInstState had a check for null address for when there are no instances.
* Make sure this never adds "null" as an address.
*/
function fetchAllInstAddrs(mod)
{
// TODO - staticInstAddrs should be constant? But clear cache deletes mod, so this won't preserve them...
/* Check if they have already been retrieved. */
if (mod.readAllAddrs) {
return;
}
var Types = xdc.module('xdc.runtime.Types');
/* Retrieve the module header, which points to all of the intstances. */
var modHdrSym = mod.name.replace(/\./g, '_') + '_Module__root__V';
var modHdrAddr = symTable.getSymbolValue(modHdrSym);
var modHdr = strDec.fetchStruct(Types.ModHdr, Number(modHdrAddr), true);
/* Create an array of the addresses of all of the static instances. */
mod.staticInstAddrs = new Array();
/* Retrieve the static instance addresses, which are in an array. */
if (modHdr.instArrBeg != 0) {
for (var instAddr = modHdr.instArrBeg;
instAddr <= modHdr.instArrEnd; instAddr += modHdr.instSize) {
mod.staticInstAddrs.$add(instAddr);
}
}
/* Create an array of the addresses of all of the dynamic instances. */
mod.dynInstAddrs = new Array();
/*
* Create a temporary map of the addresses discovered to use for detecting
* loops in the linked list.
*/
var addrs = {};
/*
* The module header is also part of a linked list of all of the
* dynamically created instances.
*/
var instHdrAddr = modHdr.link.next;
/* Loop over the list. */
while (instHdrAddr != modHdrAddr) {
/* Add the header address to the temporary map. */
addrs[instHdrAddr] = true;
/* The instance address is offset from the header. */
var instAddr = Number(instHdrAddr) + Types.InstHdr.$sizeof();
/* Add the instance's address. */
mod.dynInstAddrs.$add(instAddr);
/*
* Get the actual header struct and find the address of the
* next header struct.
*/
var instHdr = strDec.fetchStruct(Types.InstHdr, Number(instHdrAddr), true);
/* Get the address of the next instance header. */
instHdrAddr = instHdr.link.next;
/* If we've detected a loop in the instance queue throw an error. */
if (instHdrAddr in addrs) {
throw (new Error("Detected loop in instance queue at address " + instHdrAddr));
}
}
mod.readAllAddrs = true;
}
/*
* ======== getKey ========
* Makes a key out of the instance's address for the module's
* instMap.
*/
function getKey(addr)
{
return ('0x' + Number(addr).toString(16));
}
/*
* ======== fetchInstState ========
* This function scans in a single instance's state, and associates various
* metadata (used by the view$init functions) with the instance object.
* Returns the inst object for Program.scanHandle.
* This API is responsible for caching the retrieved instance states. If the
* instance state at the given address has already been read in, it will not
* be read again.
*/
function fetchInstState(mod, instAddr, staticIndex)
{
/*
* Check to see if this instance has already been scanned.
* Instances may be discovered through Program.scanInstanceView, or a call
* to Program.scanHandle from a different module's view init code; so it's
* possible that the instance has already been scanned.
*/
var key = getKey(instAddr);
if ((mod.instMap) && (key in mod.instMap)) {
return (mod.instMap[key]);
}
/*
* If this module's instance state structure has a size field, fetch the
* instance state structure.
*/
var obj;
if ('$sizeof' in mod.useMod.Instance_State) {
obj = strDec.fetchStruct(mod.useMod.Instance_State,
Number(instAddr), true);
}
/* Otherwise, this module has no real instance state (such as GateHwi). */
else {
/* TODO - Is this all right? Might it work to call fetchStruct anyway? */
Program.debugPrint("xdc.rov.decoder: Module does not have instance state.");
var temp = new mod.useMod.Instance_State;
obj = {};
obj.$addr = $addr(instAddr);
obj.$type = temp.$type;
}
/* Create an instance descriptor for the instance. */
var inst = getInstDesc(mod, obj, staticIndex);
/* Return the inst for scanHandle */
return (inst);
}
/*
* ======== getInstDesc ========
* Takes a decoded state structure and creates an ROVInstanceDesc for it.
* Also retrieves the label for the instance.
*/
function getInstDesc(mod, obj, staticIndex)
{
/*
* The instMap will map instance addresses to instance objects.
* It may already be present from a call to Program.scanHandle in a
* different module's view init code.
*/
if (!mod.instMap) {
mod.instMap = new Object();
}
/* Return immediately if this object has already been scanned. */
var key = getKey(obj.$addr);
if (key in mod.instMap) {
return (mod.instMap[key]);
}
/* Create a new instance descriptor to represent the instance */
var inst = new Program.ROVInstanceDesc;
/* Store the state structure and its address. */
inst.state = obj;
inst.addr = obj.$addr;
/* Get the instance's label */
obj.$label = getLabel(mod, obj, staticIndex);
/* Add the instance to the module's list. */
mod.instances.$add(inst);
/*
* Add the instance to the map, so we can quickly check if it's
* already been scanned.
*/
mod.instMap[key] = inst;
return (inst);
}
/*
* ======== getLabel ========
* Helper function called from getInstLabel to retrieve the label for the
* given instance.
*/
function getLabel(mod, obj, staticIndex)
{
/* Create the label for the instance. */
var label = mod.name + "@" + Number(obj.$addr).toString(16);
/* If this is a static instance, get the instance name from the capsule. */
if (staticIndex != -1) {
var givenName =
Program.$modules[mod.name].$instances[staticIndex].instance.name;
if (givenName != null) {
label += (":" + givenName);
return (label);
}
}
/* Otherwise, if this is a dynamically created instance,
* check if it has a name. */
else if('__name' in obj) {
/* If the __name field is null, no name was given. */
if(Number(obj.__name) != 0) {
try {
var givenName =
xdc.module('xdc.runtime.Text').fetchAddr(Number(obj.__name));
}
catch (e) {
if (e.message == "abort") {
throw (e);
}
/*
* Need a way to report error to user. Just display
* error instead of name.
*/
givenName = "Error retrieving given name at 0x" +
Number(obj.__name).toString(16) + ": " +
e.toString();
}
label += ":" + givenName;
return (label);
}
}
return (label);
}
/*
* ======== fetchHandleState ========
* The fetchInstState API needs to know whether the given instance
* is static or dynamic. If we just have a handle to an instance, we first
* need to determine whether it is static or dynamic.
*/
function fetchHandleState(mod, instAddr)
{
/*
* Check if this is a static instance. If it is, we need to find its index
* in the module header instance array so the decoder can retrieve the
* instance name from the recap file.
*/
fetchAllInstAddrs(mod);
var staticIndex = -1;
for (var i = 0; i < mod.staticInstAddrs.length; i++) {
if (Number(instAddr) == Number(mod.staticInstAddrs[i])) {
staticIndex = i;
break;
}
}
/* Fetch this individual instance's state, adding it to the module. */
var inst = fetchInstState(mod, instAddr, staticIndex);
return (inst);
}