369 lines
20 KiB
JavaScript
369 lines
20 KiB
JavaScript
//function takes in the device memory and a list of all registers and their associated bitfields and offsets. This is used to map the device memory values into the associated
|
|
//registers and returns the data as described below.
|
|
function parseMemoryIntoReg(deviceMemory, regMemory){
|
|
var regMemOut = '';
|
|
let regArrayLength = regMemory.length;
|
|
var sizeofregMemory = 0;
|
|
for (let i = 0; i < regArrayLength; i++) {
|
|
//Get data for current register
|
|
let regBits = regMemory[i].bits
|
|
let bitArrayLength = regBits.length;
|
|
let regOffset = regMemory[i].offset;
|
|
regOffset = parseInt(regOffset, 16) + 1; //Convert hex offset to decimal
|
|
let registerName = regMemory[i].name;
|
|
|
|
var memoryReg = "";
|
|
var regAdded = 0;
|
|
var syscfgName = "";
|
|
//Register has defined bit fields
|
|
if (bitArrayLength > 0) {
|
|
//Loop through bits of current register
|
|
for (let j = 0; j < bitArrayLength; j++) {
|
|
//Get data for current bit
|
|
let bitName = regMemory[i].bits[j].name;
|
|
sizeofregMemory += parseInt(regBits[j].size);
|
|
//Check for 32 bit register
|
|
if (regMemory[i].bits[j].size == 16) {
|
|
memoryReg = '0x' + deviceMemory[regOffset + 1].trim() + deviceMemory[regOffset].trim() //32 bit register, add next 16 bit memory
|
|
}
|
|
else {
|
|
memoryReg = '0x' + deviceMemory[regOffset].trim() //Memory at given offset is for current register
|
|
}
|
|
|
|
//Check if top-level register has been logged
|
|
if (regAdded == 0) {
|
|
regMemOut = regMemOut + registerName + ' = ' + memoryReg + '\n'; //Add register name and memory to output
|
|
regAdded = 1; //Top level register has been logged
|
|
}
|
|
//below two values are for debug only
|
|
// let regCheck = regMemory[i].bits[j].mask;
|
|
// let shift = regMemory[i].bits[j].shift;
|
|
|
|
let memoryBit = (memoryReg & regMemory[i].bits[j].mask) >> regMemory[i].bits[j].shift; //Shift register memory and apply mask to get bit result
|
|
regMemOut = regMemOut + registerName + '.' + bitName + ' = 0x' + memoryBit.toString(16).toUpperCase() + '\n'; //Add bit name and memory to output
|
|
}
|
|
}
|
|
else {
|
|
memoryReg = deviceMemory[regOffset] //Memory at given offset is for current register
|
|
regMemOut = regMemOut + registerName + ' = 0x' + memoryReg + '\n'; //Add register name and memory to output
|
|
sizeofregMemory += 16;
|
|
}
|
|
}
|
|
//cleaning data for return into format of [string object, dictionary object] wherein the dictionary object has been cleaned and seperated into values of 'name' and 'value'
|
|
var regMemoryArray = regMemOut.split('\n');
|
|
var regMemDictName = {};
|
|
let iter = 0;
|
|
while(iter < regMemoryArray.length){;
|
|
regMemoryArray[iter] = regMemoryArray[iter].replace(/\s/g, '').split('=');
|
|
regMemDictName["name"] = regMemoryArray[iter][0];
|
|
regMemDictName["value"] = regMemoryArray[iter][1];
|
|
regMemDictName["mappings"] = 0;
|
|
regMemoryArray[iter] = Object.assign({}, regMemDictName);
|
|
iter++;
|
|
}
|
|
iter = 0;
|
|
//removing unnecessary toplevel registers that cloud the data in future steps
|
|
for(let regis of regMemory){
|
|
while(iter < regMemoryArray.length){
|
|
if(regis.name == regMemoryArray[iter].name){
|
|
if(regis.bits.length != 0){
|
|
regMemoryArray.splice(iter, 1);
|
|
break;
|
|
}
|
|
else{
|
|
iter++
|
|
break;
|
|
}
|
|
}
|
|
|
|
iter++;
|
|
}
|
|
}
|
|
//removing extraneous empty array index at the end of the register mappings
|
|
if (regMemoryArray[regMemoryArray.length-1].name == ''){
|
|
regMemoryArray.pop();
|
|
}
|
|
//returning array where first object is a single string of all mappings seperated by newlines and the 2nd object is an array of dictionaries with each dictionary
|
|
//fitting into the format of 'name' and 'value' for each index with values still in their hex representation
|
|
return [regMemOut, regMemoryArray]
|
|
}
|
|
|
|
//using the mapped register memory from the above function, information about all available sysconfig options for the device, and the handler functions, this function will map
|
|
//the register memory values into their associated sysconfig option names. (as noted below, some options will have multiple entries of themselves due to some peculiarities but
|
|
//will be dealt with in later steps of the mapping process)
|
|
function parseRegIntoSyscfgMem(syscfgData1, parsedRegMem, handler_funcs){
|
|
var syscfgMemOut = "";
|
|
//regHits and sysHits are used for debug purposes to track how many registers and syscfg options are having a mapping match them
|
|
var regHits = 0;
|
|
var sysHits = 0;
|
|
//'.mappings' is used for debug purposes while '.MapHit' is used to track failings in the mapping as EVERY syscfg option should be mapped but not every register will be.
|
|
for(let i = 0; i < parsedRegMem.length; i++){
|
|
for(let sysData of syscfgData1){
|
|
//logic for if the 'register' data in the epwm.json only has a single register in it
|
|
if(parsedRegMem[i].name == sysData.register){
|
|
if("handler" in sysData){
|
|
//call handler that returns a string and boolean of if a match was hit and add to memOut and a 'skip' flag if necessary to skip over future logic blocks
|
|
if(parsedRegMem[i].mappings < 2){
|
|
let vals = handler_funcs.handlemap(parsedRegMem[i], sysData, parsedRegMem);
|
|
if (vals[0] == false){/*console.log("Handler on " + sysData.name + " does not have a case configured, please correct.");*/ continue;}
|
|
parsedRegMem[i].mappings += vals[0];
|
|
syscfgMemOut += vals[1];
|
|
sysHits++;
|
|
sysData.MapHit += 1;
|
|
if (parsedRegMem[i].mappings == 2){break;}
|
|
continue;
|
|
}
|
|
}
|
|
//when no handler is present, simple mapping between register value and the associated syscfg option name
|
|
else{
|
|
syscfgMemOut += sysData.name + " = " + parsedRegMem[i].value + '\n';
|
|
parsedRegMem[i].mappings++;
|
|
sysHits++;
|
|
sysData.MapHit += 1;
|
|
break;
|
|
}
|
|
}
|
|
//logic for if the 'register' data in the epwm.json has multiple registers in it [all multi-register settings REQUIRE handlers for functionalty]
|
|
else if(Array.isArray(sysData.register) && sysData.register.includes(parsedRegMem[i].name)){
|
|
let vals = handler_funcs.handlemap(parsedRegMem[i], sysData, parsedRegMem); //in many cases, vals[1] (the string of mapped data) WILL be empty due to the register value being not set.
|
|
//if the data mapped and the no return flag was raised with no 'MapHit's yet, then map the value into the final data.
|
|
if (vals[0] == true && vals[2] == true && sysData.MapHit == 0){
|
|
syscfgMemOut += vals[1];
|
|
}
|
|
//if the data mapped and the no return flag was raised but 'MapHit' has already been incremented, you skip mapping this into the final data.
|
|
else if (vals[0] == true && vals[2] == true && sysData.MapHit != 0){
|
|
continue;
|
|
}
|
|
//if the data mapped and the no return flag wasn't raised, always map into the final data.
|
|
else if (vals[0] == true && vals[2] == false){
|
|
syscfgMemOut += vals[1];
|
|
}
|
|
//if none of the above, either the map_handler you've written has broken OR you need to create one for this option
|
|
else{
|
|
syscfgMemOut += sysData.name + " = " + parsedRegMem[i].value + ' // VALUE HAS/NEEDS HANDLER\n';
|
|
}
|
|
parsedRegMem[i].mappings ++;
|
|
if(sysData.MapHit == 0){sysHits++;}
|
|
sysData.MapHit++;
|
|
}
|
|
}
|
|
if(parsedRegMem[i].mappings > 0){regHits++;}
|
|
}
|
|
//the below loop is predominantly for debug purposes. Helps dev to figure out which syscfg option isn't mapping to a register OR is mapping too many times.
|
|
for(let sysData of syscfgData1){
|
|
if(sysData.MapHit == 0){
|
|
syscfgMemOut += sysData.name + " // HAS NO MATCHING REGISTER ASSOCIATED, SUPPOSED REGISTER IS: " + sysData.register + '\n';
|
|
}
|
|
else if(sysData.MapHIT > 1){
|
|
syscfgMemOut += sysData.name + " // HAS MAPPED MULTIPLE TIMES, SUPPOSED REGISTER IS: " + sysData.register + '\n';
|
|
}
|
|
}
|
|
//cleaning data for return into format of [string object, dictionary object] wherein the dictionary object has been cleaned and seperated into values of 'name' and 'value'
|
|
var sysMemoryArray = syscfgMemOut.split('\n');
|
|
var sysMemDictName = {};
|
|
let iter = 0;
|
|
while(iter < sysMemoryArray.length){
|
|
//don't want options with errors to be sent into the next stage, as such they are removed from the cleaned data but remain in the printed data
|
|
if(sysMemoryArray[iter].includes("//")){
|
|
sysMemoryArray.splice(iter, 1);
|
|
}
|
|
else{
|
|
sysMemoryArray[iter] = sysMemoryArray[iter].replace(/\s/g, '').split('=');
|
|
sysMemDictName["name"] = sysMemoryArray[iter][0];
|
|
sysMemDictName["value"] = sysMemoryArray[iter][1];
|
|
sysMemoryArray[iter] = Object.assign({}, sysMemDictName);
|
|
iter++;
|
|
}
|
|
}
|
|
//removing extraneous empty array index at the end of the syscfg name mappings
|
|
if (sysMemoryArray[sysMemoryArray.length-1].name == ''){
|
|
sysMemoryArray.pop();
|
|
}
|
|
//returning array where first object is a single string of all mappings seperated by newlines and the 2nd object is an array of dictionaries with each dictionary
|
|
//fitting into the format of 'name' and 'value' for each index with values still in their hex representation
|
|
return [syscfgMemOut, sysMemoryArray];
|
|
}
|
|
|
|
function parseSyscfgMemToValues(parsedSyscfgData, enumData, sysOptions){
|
|
var mappedMemoryOut = "";
|
|
//mappedHits is used for debug and testing purposes to help devs see what total percentage of syscfg options with register mappings have value mappings
|
|
var mappedHits = 0;
|
|
for(let sysData of parsedSyscfgData){
|
|
let reset = 0;
|
|
let hit = 0;
|
|
let selOption = sysOptions[sysData.name];
|
|
//the process for mapping does NOT work without a default value, so creating a temporary default for this without one and then resetting it afterwards
|
|
if(selOption.default.length == 0){
|
|
selOption.default = selOption.options[0].name;
|
|
reset = 1;
|
|
}
|
|
//dealing with mapping values with a default value that is an integer or string representation of one
|
|
if(selOption.default === 0 || selOption.default === '0'){
|
|
let decValue = parseInt(sysData.value, 16);
|
|
mappedMemoryOut += sysData.name + " = " + decValue + '\n';
|
|
mappedHits++;
|
|
hit = 1;
|
|
}
|
|
//due to the mapping only currently working for a single peripheral at a time right now (for example, can only map EPWM1 or EPWM2, not both at once), the linking setting
|
|
//is impossible to match though hopefully will be added back in with future functionality increases
|
|
else if(selOption.default == 'EPWM_LINK_WITH_DISABLE'){
|
|
mappedMemoryOut += sysData.name + " = " + selOption.default + '\n';
|
|
mappedHits++;
|
|
hit = 1;
|
|
}
|
|
//dealing with mapping values with a default value that is a boolean
|
|
else if(selOption.default === false){
|
|
if(parseInt(sysData.value, 16) == 0){
|
|
mappedMemoryOut += sysData.name + " = " + "false\n";
|
|
mappedHits++;
|
|
hit = 1;
|
|
}
|
|
else if(parseInt(sysData.value, 16) == 1){
|
|
mappedMemoryOut += sysData.name + " = " + "true\n";
|
|
mappedHits++;
|
|
hit = 1;
|
|
}
|
|
//debugging failures in mapping boolean values
|
|
else{
|
|
console.log("Error. Issue with boolean value register setting.")
|
|
}
|
|
}
|
|
//dealing with mapping values with a default value that is a boolean (same logic as above but 'flipped')
|
|
else if(selOption.default === true){
|
|
if(parseInt(sysData.value, 16) == 0){
|
|
mappedMemoryOut += sysData.name + " = " + "true\n";
|
|
mappedHits++;
|
|
hit = 1;
|
|
}
|
|
else if(parseInt(sysData.value, 16) == 1){
|
|
mappedMemoryOut += sysData.name + " = " + "false\n";
|
|
mappedHits++;
|
|
hit = 1;
|
|
}
|
|
//debugging failures in mapping boolean values
|
|
else{
|
|
console.log("Error. Issue with boolean value register setting.")
|
|
}
|
|
}
|
|
//for all other cases, as in default values that are not integers or booleans, the process consists of finding the default value of a setting within the enumerated values
|
|
//as their is no simple direct mapping and then, by using the value stored with each setting name, mapping the correct syscfg option value to name.
|
|
else{
|
|
for(let enums in enumData){
|
|
let selEnums = enumData[enums];
|
|
for(let i = 0; i < selEnums.length; i++){
|
|
let checker = selEnums[i]
|
|
if (selEnums[i].name == selOption.default){
|
|
for(let j = 0; j < selEnums.length; j++){
|
|
if(parseInt(sysData.value, 16) == selEnums[j].value){
|
|
mappedMemoryOut += sysData.name + " = " + selEnums[j].name + '\n';
|
|
mappedHits++;
|
|
hit = 1;
|
|
break;
|
|
}
|
|
else if (sysData.value == selEnums[j].value){
|
|
mappedMemoryOut += sysData.name + " = " + selEnums[j].name + '\n';
|
|
mappedHits++;
|
|
hit = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//the 'hit == 1' breaks are to make the logic function quicker once its found a match rather than going through every piece of data every time
|
|
if(hit == 1){break;}
|
|
}
|
|
if(hit == 1){break;}
|
|
}
|
|
}
|
|
//debug setting to help devs figure out which syscfg options didn't map to an enumerated value
|
|
if(hit != 1){
|
|
//console.log("This setting did NOT map to any non-boolean value: " + sysData.name);
|
|
}
|
|
//resetting the defaults for those without a default as mentioned above
|
|
if(reset == 1){
|
|
selOption.default = [];
|
|
}
|
|
}
|
|
//cleaning data for return into format of [string object, dictionary object] wherein the dictionary object has been cleaned and seperated into values of 'name' and 'value'
|
|
var mapMemoryArray = mappedMemoryOut.split('\n');
|
|
var mapMemDictName = {};
|
|
let iter = 0;
|
|
while(iter < mapMemoryArray.length){;
|
|
mapMemoryArray[iter] = mapMemoryArray[iter].replace(/\s/g, '').split('=');
|
|
mapMemDictName["name"] = mapMemoryArray[iter][0];
|
|
mapMemDictName["value"] = mapMemoryArray[iter][1];
|
|
if(mapMemDictName["value"] == "false"){mapMemDictName["value"] = false;}
|
|
else if(mapMemDictName["value"] == "true"){mapMemDictName["value"] = true;}
|
|
mapMemoryArray[iter] = Object.assign({}, mapMemDictName);
|
|
//because some values have multiple mappings that require them to be stored within an array, we must check every step of the way for multiple options with the same name
|
|
//and either create the array to store them OR if this has already been done, push the value onto the array
|
|
if(iter > 0 && mapMemoryArray[iter].name == mapMemoryArray[iter-1].name){
|
|
if(typeof (mapMemoryArray[iter-1].value) == "string"){
|
|
let arrayHold = [];
|
|
mapMemoryArray[iter-1].value = mapMemoryArray[iter-1].value.replace(';', '');
|
|
mapMemoryArray[iter].value = mapMemoryArray[iter].value.replace(';', '');
|
|
arrayHold.push(mapMemoryArray[iter-1].value);
|
|
arrayHold.push(mapMemoryArray[iter].value);
|
|
mapMemoryArray[iter-1].value = Object.assign([], arrayHold);
|
|
}
|
|
else{
|
|
mapMemoryArray[iter].value = mapMemoryArray[iter].value.replace(';', '');
|
|
mapMemoryArray[iter-1].value.push(mapMemoryArray[iter].value);
|
|
}
|
|
mapMemoryArray.splice(iter, 1);
|
|
continue;
|
|
}
|
|
iter++;
|
|
}
|
|
//removing extraneous empty array index at the end of the syscfg value mappings
|
|
if (mapMemoryArray[mapMemoryArray.length-1].name == ''){
|
|
mapMemoryArray.pop();
|
|
}
|
|
//for the VAST majority of syscfg options in most cases, they will still be in their default value. We ONLY care about the non-default values as those are what will be put
|
|
//into sysconfig AND be used for testing purposes against the testbank of data. As a result, the below block checks default values against the mapped values to see if they
|
|
//should be mapped through to the final step. For options with NO default (typically shown as an empty array), if ANYTHING is set, then consider it non-default. Every other
|
|
//default type uses direct matching to check.
|
|
let mappedMemNoDefaults = [];
|
|
for(let mapDicts of mapMemoryArray){
|
|
let options = sysOptions[mapDicts.name].default;
|
|
if (Array.isArray(mapDicts.value)){mappedMemNoDefaults.push(mapDicts);}
|
|
if (options === [] && !(mapDicts.value)){
|
|
mappedMemNoDefaults.push(mapDicts);
|
|
}
|
|
else if (mapDicts.value === false || mapDicts.value === true){
|
|
if(options === mapDicts.value){
|
|
continue;
|
|
}
|
|
else{
|
|
mappedMemNoDefaults.push(mapDicts);
|
|
}
|
|
}
|
|
else if ( typeof mapDicts.value == 'string'){
|
|
if (options == mapDicts.value){
|
|
continue;
|
|
}
|
|
else if(options.toString() == mapDicts.value){
|
|
continue;
|
|
}
|
|
else{
|
|
mappedMemNoDefaults.push(mapDicts);
|
|
}
|
|
}
|
|
}
|
|
//for debug purposes, all of the non-default data is stored within a string with newlines in the exact same format as the string of default and non-default data.
|
|
var noDefaults = '';
|
|
for(let mapDicts of mappedMemNoDefaults){
|
|
noDefaults += mapDicts.name + " = " + mapDicts.value + '\n';
|
|
}
|
|
// console.log("Percentage Final Mapped = " + (mappedHits/parsedSyscfgData.length)*100 + "%");
|
|
//returning array where first object is a single string of all mappings seperated by newlines and the 2nd object is an array of dictionaries with each dictionary
|
|
//fitting into the format of 'name' and 'value' for each index with values still in their hex representation. The 3rd object is an array of dictionaries with the exact same
|
|
//structure as the 2nd object but for ONLY non-default values and the 4th object is a string of all non-default mappigns seperated by newlines.
|
|
return [mappedMemoryOut, mapMemoryArray, mappedMemNoDefaults, noDefaults];
|
|
}
|
|
|
|
//The mapping process has been split into three different functions as described above.
|
|
module.exports = {
|
|
parseMemoryIntoReg : parseMemoryIntoReg,
|
|
parseRegIntoSyscfgMem : parseRegIntoSyscfgMem,
|
|
parseSyscfgMemToValues : parseSyscfgMemToValues
|
|
}; |