LCOV - code coverage report
Current view: top level - mu2e-pcie-utils/cfoInterfaceLib - CFO_Compiler.cpp (source / functions) Coverage Total Hit
Test: mu2edaq.info.cleaned Lines: 0.0 % 643 0
Test Date: 2026-07-30 01:56:44 Functions: 0.0 % 136 0

            Line data    Source code
       1              : #include "cfoInterfaceLib/CFO_Compiler.hh"
       2              : 
       3              : #include <iostream>
       4              : #include <set>
       5              : 
       6              : #define TRACE_NAME "CFO_Compiler"
       7              : 
       8              : #include "dtcInterfaceLib/otsStyleCoutMacros.h"
       9              : 
      10              : template<class T>
      11              : std::string vectorToString(  // defined in included .icc source
      12              :         const std::vector<T>& setToReturn,
      13              :         const std::string& delimeter = ", ");
      14              : 
      15              : void getVectorFromString(
      16              :         const std::string& inputString,
      17              :         std::vector<std::string>& listToReturn,
      18              :         const std::set<char>& delimiter = {',', '|', '&'},
      19              :         const std::set<char>& whitespace = {' ', '\t', '\n', '\r'},
      20              :         std::vector<char>* listOfDelimiters = 0 /*,
      21              : //bool                                                                                                  decodeURIComponents = false */
      22              : );
      23              : 
      24              : template<class T>
      25              : bool getNumber(const std::string& s, T& retValue);
      26              : 
      27              : const std::string CFOLib::CFO_Compiler::MAIN_GOTO_LABEL = "MAIN";
      28              : 
      29              : const uint64_t CFOLib::CFO_Compiler::FPGAClock_ = (1e9 / (40e6) /* 40MHz FPGAClock for calculating delays */);  // period of FPGA clock in ns
      30              : 
      31              : //========================================================================
      32            0 : std::string CFOLib::CFO_Compiler::processFile(const std::string& sourceCodeFile,
      33              :                                                                                           const std::string& binaryOutputFile)
      34              : try
      35              : {
      36            0 :         __COUT_INFO__ << "CFO_Compiler::processFile BEGIN";
      37              : 
      38            0 :         FILE* fp = fopen(sourceCodeFile.c_str(), "r");
      39            0 :         if (!fp)
      40              :         {
      41            0 :                 __SS__ << "Input File (" << sourceCodeFile << ") didn't open. Does it exist?" << __E__;
      42            0 :                 __SS_THROW__;
      43            0 :         }
      44              : 
      45            0 :         std::string line;
      46              :         char lineChars[100];
      47              : 
      48            0 :         txtLineNumber_ = 0;
      49            0 :         binLineNumber_ = 0;
      50            0 :         hasRequiredPlanEndOp_ = false;  // require at least one END, REPEAT, or GOTO MAIN command to give a handle on switch Run Plan buffers to the CFO firmware
      51              : 
      52            0 :         loopStack_.clear();
      53            0 :         labelMap_.clear();
      54              : 
      55            0 :         output_.clear();
      56              : 
      57              :         // main line processing loop
      58            0 :         while (fgets(lineChars, 100, fp))
      59              :         {
      60            0 :                 line = lineChars;
      61            0 :                 while (strlen(lineChars) && lineChars[strlen(lineChars) - 1] != '\n' && fgets(lineChars, 100, fp))
      62            0 :                         line += lineChars;
      63              : 
      64            0 :                 ++txtLineNumber_;
      65            0 :                 __COUTT__ << "Line number " << txtLineNumber_ << ": " << line << __E__;
      66              : 
      67            0 :                 if (isComment(line))
      68              :                 {
      69            0 :                         __COUTT__ << txtLineNumber_ << ": is comment" << __E__;
      70            0 :                         continue;
      71            0 :                 }
      72              : 
      73              :                 // read all arguments
      74            0 :                 opArguments_.clear();
      75            0 :                 getVectorFromString(line, opArguments_,
      76              :                                                         {',', ' ', '\t', ';', '='} /*delimiter*/,
      77              :                                                         {'\n', '\r'} /*white space (empty because white space is a delimiter)*/);
      78              : 
      79              :                 // clean up empty strings (because of white space delimiter) and comments
      80            0 :                 for (size_t i = 0; i < opArguments_.size(); ++i)
      81            0 :                         if (opArguments_[i].length() == 0)
      82            0 :                                 opArguments_.erase(opArguments_.begin() + i--);  // erase and rewind
      83            0 :                         else if (opArguments_[i].length() >= 2 &&
      84            0 :                                          opArguments_[i][0] == '/' && opArguments_[i][1] == '/')  // comment to the end
      85              :                         {
      86              :                                 // erase remainder of arguments because they are commented out
      87            0 :                                 while (i < opArguments_.size())
      88            0 :                                         opArguments_.erase(opArguments_.begin() + i);  // erase
      89            0 :                                 break;
      90              :                         }
      91              : 
      92            0 :                 __COUTTV__(opArguments_.size());
      93            0 :                 __COUTTV__(vectorToString(opArguments_));
      94              : 
      95            0 :                 if (!opArguments_.size())  // skip no arguments
      96              :                 {
      97            0 :                         __COUTT__ << txtLineNumber_ << ": is empty" << __E__;
      98            0 :                         continue;
      99            0 :                 }
     100              : 
     101              :                 // CFOLib::CFO_Compiler::CFO_MACRO macroOpTest = parseMacro(opArguments_[0]);
     102              :                 // if(macroOpTest == CFO_MACRO::NON_MACRO)
     103            0 :                 processOp();
     104              :                 // else
     105              :                 //      processMacro(macroOpTest);
     106              : 
     107              :         }  // end main processing loop
     108              : 
     109            0 :         if (!hasRequiredPlanEndOp_)
     110              :         {
     111            0 :                 __SS__ << "The Run Plan is missing an concluding operation that can be used as a moment to dynamically swith to the next run plan."
     112            0 :                                   " At least one of these commands is required in your run plan: END, REPEAT, or GOTO MAIN."
     113            0 :                            << __E__;
     114            0 :                 __SS_THROW__;
     115            0 :         }
     116              : 
     117            0 :         std::stringstream resultSs;
     118            0 :         resultSs << "Run plan text file: " << sourceCodeFile << __E__ << "was compiled to binary: " << binaryOutputFile << __E__;
     119            0 :         resultSs << "\n\nBinary Result (Op count = " << output_.size() / 8 << "):\n";
     120            0 :         int cnt = 0;
     121              : 
     122              :         // to view output file with 8-byte rows
     123              :         // hexdump -e '"%08_ax " 1/8 "%016x "' -e '"\n"' srcs/mu2e_pcie_utils/cfoInterfaceLib/Commands.bin
     124            0 :         std::ofstream outFile;
     125            0 :         outFile.open(binaryOutputFile.c_str(), std::ios::out | std::ios::binary);
     126              : 
     127            0 :         if (!(outFile.is_open()))
     128              :         {
     129            0 :                 __SS__ << "Output File (" << binaryOutputFile << ") didn't open. Does it exist?" << __E__;
     130            0 :                 __SS_THROW__;
     131            0 :         }
     132              :         char outStr[20];
     133            0 :         std::string binaryLine;  // build least-significant byte on right display
     134            0 :         std::string tabStr = "";
     135            0 :         int markerCnt = 0;
     136            0 :         int binaryLineNumber = 0;
     137            0 :         for (auto c : output_)
     138              :         {
     139            0 :                 outFile << c;
     140            0 :                 if (cnt % 8 == 0)
     141              :                 {
     142            0 :                         binaryLine = "";  // clear
     143            0 :                         sprintf(outStr, "%5d", (cnt / 8 + 1));
     144              :                         resultSs << "\n"
     145            0 :                                          << tabStr << outStr << ": 0x";
     146              :                 }
     147            0 :                 else if (cnt % 4 == 0)
     148            0 :                         binaryLine = " " + binaryLine;
     149              : 
     150            0 :                 sprintf(outStr, "%2.2x", (uint16_t)c & 0x0FF);
     151            0 :                 binaryLine = outStr + binaryLine;
     152              : 
     153              :                 // show command for easier human understanding of binary
     154            0 :                 if (cnt % 8 == 7)  // last byte in output is most-significant (and the opcode)
     155              :                 {
     156            0 :                         auto instr = CFOLib::CFO_Compiler::CFO_INSTR(c);
     157            0 :                         resultSs << binaryLine << "     // " << translateOpCode(instr);
     158            0 :                         if (instr == CFO_INSTR::MARKER)
     159            0 :                                 resultSs << " -----> #" << ++markerCnt;
     160            0 :                         __COUTT__ << "binaryLine #" << ++binaryLineNumber << " = " << binaryLine << __E__;
     161            0 :                         if (instr == CFO_INSTR::LOOP)
     162            0 :                                 tabStr += '\t';
     163            0 :                         else if (instr == CFO_INSTR::DO_LOOP && tabStr.length())
     164            0 :                                 tabStr = tabStr.substr(0, tabStr.length() - 1);
     165              :                 }
     166              : 
     167            0 :                 ++cnt;
     168              :         }
     169            0 :         resultSs << "\n";
     170            0 :         outFile.close();
     171              : 
     172              :         // to view output file with 8-byte rows
     173              :         // hexdump -e '"%08_ax " 1/8 "%016x "' -e '"\n"' srcs/mu2e_pcie_utils/cfoInterfaceLib/Commands.bin
     174              : 
     175            0 :         __COUT_INFO__ << "CFO_Compiler::processFile Parsing Complete!";
     176            0 :         return resultSs.str();
     177            0 : }  // end processFile()
     178            0 : catch (const std::runtime_error& e)
     179              : {
     180            0 :         __SS__ << "Error caught wile compiling source text at '"
     181              :                    << "<FILE>" << sourceCodeFile << "</FILE>' into binary run plan at '"
     182              :                    << "<FILE>" << binaryOutputFile << "</FILE>.'\n"
     183            0 :                    << e.what() << __E__;
     184              : 
     185            0 :         __SS_THROW__;
     186            0 : }
     187            0 : catch (...)
     188              : {
     189            0 :         __SS__ << "Unknown error caught wile compiling source text at '"
     190              :                    << "<FILE>" << sourceCodeFile << "</FILE>' into binary run plan at '"
     191            0 :                    << "<FILE>" << binaryOutputFile << "</FILE>.'\n"
     192            0 :                    << __E__;
     193              :         try
     194              :         {
     195            0 :                 throw;
     196              :         }  // one more try to printout extra info
     197            0 :         catch (const std::exception& e)
     198              :         {
     199            0 :                 ss << "Exception message: " << e.what();
     200            0 :         }
     201            0 :         catch (...)
     202            0 :         {}
     203            0 :         __COUT_ERR__ << "\n"
     204            0 :                                  << ss.str();
     205            0 :         throw;
     206            0 : }  // end processFile() error handling
     207              : 
     208              : //========================================================================
     209              : // Boolean Operators
     210            0 : bool CFOLib::CFO_Compiler::isComment(const std::string& line)  // Checks if line has a comment.
     211              : {
     212            0 :         for (size_t i = 0; i < line.length() - 1; ++i)
     213              :         {
     214            0 :                 if (line[i] == ' ' ||
     215            0 :                         line[i] == '\t' ||
     216            0 :                         line[i] == '\r' ||
     217            0 :                         line[i] == '\n') continue;  // skip white space
     218              : 
     219            0 :                 if (line[i] != '/') return false;  // some non-comment char found
     220            0 :                 if (line[i + 1] != '/')
     221              :                 {
     222            0 :                         __SS__ << "Single slash found; missing double slash for comment. (Line " << txtLineNumber_ << ")" << __E__;
     223            0 :                         __SS_THROW__;
     224            0 :                 }
     225            0 :                 return true;  // comment // string found
     226              :         }
     227            0 :         return true;  // for empty string, consider as comment
     228              : }  // end isComment()
     229              : 
     230              : const std::map<std::string, CFOLib::CFO_Compiler::CFO_INSTR> CFOLib::CFO_Compiler::OP_to_CODE_TRANSLATION = {
     231              :         {"HEARTBEAT", CFO_INSTR::HEARTBEAT},
     232              :         {"MARKER", CFO_INSTR::MARKER},
     233              :         {"DATA_REQUEST", CFO_INSTR::DATA_REQUEST},
     234              :         {"SET_TAG", CFO_INSTR::SET_TAG},
     235              :         {"INC_TAG", CFO_INSTR::INC_TAG},
     236              :         {"LOOP", CFO_INSTR::LOOP},
     237              :         {"DO_LOOP", CFO_INSTR::DO_LOOP},
     238              :         {"REPEAT", CFO_INSTR::REPEAT},
     239              :         {"WAIT", CFO_INSTR::WAIT},
     240              :         {"END", CFO_INSTR::END},
     241              :         {"GOTO_LABEL", CFO_INSTR::GOTO},
     242              :         {"LABEL", CFO_INSTR::LABEL},
     243              :         {"CLEAR_MODE_BITS", CFO_INSTR::CLEAR_MODE_BITS},
     244              :         {"SET_MODE_BITS", CFO_INSTR::SET_MODE_BITS},
     245              :         {"AND_MODE_BITS", CFO_INSTR::AND_MODE_BITS},
     246              :         {"OR_MODE_BITS", CFO_INSTR::OR_MODE_BITS},
     247              :         {"OR_SINGLESHOT_MODE_BITS", CFO_INSTR::OR_SINGLESHOT_MODE_BITS},
     248              :         {"SET_MODE", CFO_INSTR::SET_MODE},
     249              : };
     250              : 
     251              : //========================================================================
     252              : // Switch Conversions
     253              : // Turns strings into integers for switch statements.
     254            0 : CFOLib::CFO_Compiler::CFO_INSTR CFOLib::CFO_Compiler::parseInstruction(const std::string& op)
     255              : {
     256              :         try
     257              :         {
     258            0 :                 return OP_to_CODE_TRANSLATION.at(op);
     259              :         }
     260            0 :         catch (...)
     261              :         {
     262            0 :                 return CFO_INSTR::INVALID;
     263            0 :         }
     264              : }  // end parseInstruction()
     265              : 
     266              : const std::map<uint8_t, std::string> CFOLib::CFO_Compiler::CODE_to_OP_TRANSLATION = {
     267              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::HEARTBEAT, "HEARTBEAT"},
     268              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::MARKER, "MARKER"},
     269              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::DATA_REQUEST, "DATA_REQUEST"},
     270              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::SET_TAG, "SET_TAG"},
     271              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::INC_TAG, "INC_TAG"},
     272              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::LOOP, "LOOP"},
     273              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::DO_LOOP, "DO_LOOP"},
     274              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::REPEAT, "REPEAT"},
     275              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::WAIT, "WAIT"},
     276              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::END, "END"},
     277              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::GOTO, "GOTO_LABEL"},
     278              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::LABEL, "LABEL"},
     279              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::NOOP, "LABEL"},
     280              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::CLEAR_MODE_BITS, "CLEAR_MODE_BITS"},
     281              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::SET_MODE_BITS, "SET_MODE_BITS"},
     282              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::AND_MODE_BITS, "AND_MODE_BITS"},
     283              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::OR_MODE_BITS, "OR_MODE_BITS"},
     284              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::OR_SINGLESHOT_MODE_BITS, "OR_SINGLESHOT_MODE_BITS"},
     285              :         {(uint8_t)CFOLib::CFO_Compiler::CFO_INSTR::SET_MODE, "SET_MODE"},
     286              : };
     287              : 
     288              : //========================================================================
     289            0 : const std::string& CFOLib::CFO_Compiler::translateOpCode(CFOLib::CFO_Compiler::CFO_INSTR opCode)
     290              : {
     291              :         try
     292              :         {
     293            0 :                 return CODE_to_OP_TRANSLATION.at((uint8_t)opCode);
     294              :         }
     295            0 :         catch (...)
     296              :         {
     297            0 :                 __SS__ << "No tranlation found for opCode " << (int)opCode << __E__;
     298            0 :                 __SS_THROW__;
     299            0 :         }
     300              : }  // end translateOpCode()
     301              : 
     302              : //========================================================================
     303            0 : void CFOLib::CFO_Compiler::outParameter(uint64_t paramBuf)  // Writes the 6 byte parameter out based on a given integer.
     304              : {
     305            0 :         paramBuf &= 0xFFFFFFFFFFFF;  // Enforce 6 bytes
     306            0 :         auto paramBufPtr = reinterpret_cast<int8_t*>(&paramBuf);
     307            0 :         for (int i = 0; i < 6; ++i)
     308              :         {
     309            0 :                 output_.push_back(paramBufPtr[i]);
     310            0 :                 __COUTT__ << "[" << output_.size() << "] ==> output_ 0x" << std::hex << ((uint16_t)output_.back() & 0x0FF) << __E__;
     311              :         }
     312            0 : }  // end outParameter()
     313              : 
     314              : //========================================================================
     315              : // processOp
     316              : //              Outputs a byte stream based on the buffers.
     317              : //              opArguments_ must be checked before to be size >= 1
     318            0 : void CFOLib::CFO_Compiler::processOp()
     319              : {
     320              :         // calculate line numbers that match this hexdump call (all usage of bin is relative/differences):
     321              :         //              hexdump -e '"%08_ax | " 1/8 "%016x "' -e '"\n"'  CFOCommands.bin | cat -n
     322            0 :         binLineNumber_ = 1 + output_.size() / 8;
     323            0 :         __COUTT__ << "binLineNumber_: " << (int)binLineNumber_ << __E__;
     324              : 
     325            0 :         CFO_INSTR instructionOpcode = parseInstruction(opArguments_[0]);
     326            0 :         if (instructionOpcode == CFO_INSTR::INVALID)
     327              :         {
     328            0 :                 __SS__ << "On Line " << txtLineNumber_ << ", invalid instruction '" << opArguments_[0] << "' found. " << __E__;
     329            0 :                 __SS_THROW__;
     330            0 :         }
     331              : 
     332            0 :         int64_t parameterCalc = calculateParameterAndErrorCheck(instructionOpcode);
     333            0 :         __COUTTV__((int)instructionOpcode);
     334            0 :         __COUTTV__(parameterCalc);
     335              : 
     336            0 :         if (instructionOpcode == CFO_INSTR::SET_MODE_BITS ||
     337              :                 instructionOpcode == CFO_INSTR::SET_MODE)
     338              :         {
     339            0 :                 __COUTT__ << "MASK off 0x" << std::hex << modeClearMask_ << __E__;
     340              :                 // treat as two ops: an AND and an OR
     341            0 :                 outParameter(modeClearMask_);
     342            0 :                 output_.push_back(0x00);
     343            0 :                 __COUTT__ << "[" << output_.size() << "] ==> output_ 0x" << std::hex << std::setfill('0') << std::setprecision(2) << (uint16_t)output_.back() << __E__;
     344            0 :                 output_.push_back(static_cast<char>(CFO_INSTR::AND_MODE_BITS));
     345            0 :                 __COUTT__ << "[" << output_.size() << "] ==> output_ 0x" << std::hex << std::setfill('0') << std::setprecision(2) << (uint16_t)output_.back() << __E__;
     346              : 
     347            0 :                 instructionOpcode = CFO_INSTR::OR_MODE_BITS;
     348            0 :                 __COUTT__ << "MASK on 0x" << std::hex << parameterCalc << __E__;
     349              :         }
     350              : 
     351            0 :         outParameter(parameterCalc);
     352              : 
     353            0 :         if (instructionOpcode == CFO_INSTR::REPEAT ||
     354            0 :                 instructionOpcode == CFO_INSTR::END ||
     355              :                 instructionOpcode == CFO_INSTR::GOTO)
     356            0 :                 hasRequiredPlanEndOp_ = true;
     357            0 :         else if (instructionOpcode == CFO_INSTR::LABEL)  // in binary, treat as NOOP
     358            0 :                 instructionOpcode = CFO_INSTR::NOOP;
     359            0 :         else if (instructionOpcode == CFO_INSTR::CLEAR_MODE_BITS)  // treat clear as AND
     360            0 :                 instructionOpcode = CFO_INSTR::AND_MODE_BITS;
     361              : 
     362            0 :         output_.push_back(0x00);
     363            0 :         __COUTT__ << "[" << output_.size() << "] ==> output_ 0x" << std::hex << std::setfill('0') << std::setprecision(2) << (uint16_t)output_.back() << __E__;
     364            0 :         output_.push_back(static_cast<char>(instructionOpcode));
     365            0 :         __COUTT__ << "[" << output_.size() << "] ==> output_ 0x" << std::hex << std::setfill('0') << std::setprecision(2) << (uint16_t)output_.back() << __E__;
     366              : 
     367            0 : }  // end processOp()
     368              : 
     369              : //========================================================================
     370              : // Parameter Calculations
     371              : //      Calculates the parameter for the instruction (if needed) and does error checking
     372            0 : uint64_t CFOLib::CFO_Compiler::calculateParameterAndErrorCheck(CFO_INSTR instructionOpcode)
     373              : {
     374            0 :         size_t opArgCount = opArguments_.size();
     375            0 :         modeClearMask_ = 0;  // clear
     376              : 
     377            0 :         __COUTT__ << "calculateParameterAndErrorCheck... Instruction: " << opArguments_[0] << ", Parameter count: " << opArgCount << __E__;
     378              : 
     379              :         uint64_t value;
     380              : 
     381            0 :         switch (instructionOpcode)
     382              :         {
     383            0 :                 case CFO_INSTR::HEARTBEAT:
     384            0 :                         if (opArgCount != 3 || opArguments_[1] != "event_mode")
     385              :                         {
     386            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 1 named parameter, and " << opArgCount / 2 << " were found. Here is the syntax := \"" << opArguments_[0] << " event_mode=[value]\" ... "
     387              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         "The source instruction was \""
     388            0 :                                            << vectorToString(opArguments_, " " /*delimieter*/) << ".\"\n\n"
     389              :                                                                                                                                                           "The event_mode value can be the string \"registered\" to use the locally maintained event_mode value of the compiler,"
     390            0 :                                                                                                                                                           " otherwise a number (hex 0x### and binary b### syntax allowed) for event_mode should be specified (0 for null HEARTBEAT)."
     391            0 :                                            << __E__;
     392            0 :                                 __SS_THROW__;
     393            0 :                         }
     394              : 
     395            0 :                         if (opArguments_[2] == "registered")
     396            0 :                                 return -1;  // indicate to FPGA to use registered event mode
     397              : 
     398            0 :                         if (!getNumber(opArguments_[2], value))
     399              :                         {
     400            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), for instruction '" << opArguments_[0] << ",' "
     401            0 :                                            << "the parameter value '" << opArguments_[1] << " = " << opArguments_[2] << "' is not a valid number. "
     402            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     403            0 :                                 __SS_THROW__;
     404            0 :                         }
     405            0 :                         return value;
     406              : 
     407            0 :                 case CFO_INSTR::MARKER:
     408            0 :                         if (opArgCount != 1)
     409              :                         {
     410            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", '" << opArguments_[0] << "' has extraneous arguments; there must be no additional arguments." << std::endl;
     411            0 :                                 __SS_THROW__;
     412            0 :                         }
     413            0 :                         break;
     414              : 
     415            0 :                 case CFO_INSTR::DATA_REQUEST:
     416            0 :                         if (opArgCount != 3 || opArguments_[1] != "request_tag")
     417              :                         {
     418            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 1 named parameter, and " << opArgCount / 2 << " were found. Here is the syntax := \"" << opArguments_[0] << " request_tag=[value]\n\n\""
     419              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         " The request_tag value can be the string \"current\" to request the most recent Event Window Tag data,"
     420            0 :                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         " otherwise a number (hex 0x### and binary b### syntax allowed) for request_tag should be specified."
     421            0 :                                            << __E__;
     422            0 :                                 __SS_THROW__;
     423            0 :                         }
     424            0 :                         if (opArguments_[2] == "current")
     425            0 :                                 return -1;
     426            0 :                         if (!getNumber(opArguments_[2], value))
     427              :                         {
     428            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), for instruction '" << opArguments_[0] << ",' "
     429            0 :                                            << "the parameter value '" << opArguments_[1] << " = " << opArguments_[2] << "' is not a valid number. "
     430            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     431            0 :                                 __SS_THROW__;
     432            0 :                         }
     433            0 :                         return value;
     434              : 
     435            0 :                 case CFO_INSTR::SET_TAG:
     436            0 :                         if (opArgCount != 2)
     437              :                         {
     438            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 2 arguments, and " << opArgCount << " were found. Here is the syntax := \"" << opArguments_[0] << " [value]\" ... "
     439              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                   "The source instruction was \""
     440            0 :                                            << vectorToString(opArguments_, " " /*delimieter*/) << ".\"\n\n"
     441            0 :                                                                                                                                                           "For the set tag number, hex 0x### and binary b### syntax is allowed, otherwise decimal is inferred."
     442            0 :                                            << __E__;
     443            0 :                                 __SS_THROW__;
     444            0 :                         }
     445            0 :                         if (!getNumber(opArguments_[1], value))
     446              :                         {
     447            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), for instruction '" << opArguments_[0] << ",' "
     448            0 :                                            << "the parameter value '" << opArguments_[1] << "' is not a valid number. "
     449            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     450            0 :                                 __SS_THROW__;
     451            0 :                         }
     452            0 :                         return value;
     453              : 
     454            0 :                 case CFO_INSTR::INC_TAG:
     455            0 :                         if (opArgCount == 1)  // default to increment by 1 if no value
     456            0 :                                 return 1;
     457            0 :                         if (opArgCount != 3 || opArguments_[1] != "add_value")
     458              :                         {
     459            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 0 or 1 named parameter, and " << opArgCount << " were found. Here is the syntax := \"" << opArguments_[0] << " add_value=[value]\" ... "
     460              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          "The source instruction was \""
     461            0 :                                            << vectorToString(opArguments_, " " /*delimieter*/) << ".\"\n\n"
     462              :                                                                                                                                                           " If no named parameter, then increment by 1 is assumed,"
     463            0 :                                                                                                                                                           " otherwise a number (hex 0x### and binary b### syntax allowed) for add_value should be specified."
     464            0 :                                            << __E__;
     465            0 :                                 __SS_THROW__;
     466            0 :                         }
     467              : 
     468            0 :                         if (!getNumber(opArguments_[2], value))
     469              :                         {
     470            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), for instruction '" << opArguments_[0] << ",' "
     471            0 :                                            << "the parameter value '" << opArguments_[1] << " = " << opArguments_[2] << "' is not a valid number. "
     472            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     473            0 :                                 __SS_THROW__;
     474            0 :                         }
     475            0 :                         return value;
     476              : 
     477            0 :                 case CFO_INSTR::WAIT: {
     478            0 :                         if (opArgCount != 3 ||
     479            0 :                                 (opArguments_[2] != "clocks" && opArguments_[2] != "ns" &&
     480            0 :                                  opArguments_[2] != "s" && opArguments_[2] != "ms" && opArguments_[2] != "us" &&
     481            0 :                                  opArguments_[2] != "RF0") ||
     482            0 :                                 (opArguments_[1] != "NEXT" && opArguments_[2] == "RF0"))
     483              :                         {
     484            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 3 arguments, and " << opArgCount << " were found. Here is the syntax := \"" << opArguments_[0] << " [value] [units]\" or \"" << opArguments_[0] << " NEXT RF0\" ... "
     485              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    "The source instruction was \""
     486            0 :                                            << vectorToString(opArguments_, " " /*delimieter*/) << ".\"\n\n"
     487              :                                                                                                                                                           "For the units, accepted unit strings are clocks, ns, us, ms, and s.\n\n"
     488            0 :                                            << "If NEXT RF0 is provided, then the '" << opArguments_[0] << "' will last until the next RF-0 accelerator marker is received.\n\n"
     489            0 :                                            << "For the wait value, hex 0x### and binary b### syntax is allowed, otherwise decimal is inferred." << __E__;
     490            0 :                                 __SS_THROW__;
     491            0 :                         }
     492            0 :                         if (opArguments_[1] == "NEXT")
     493            0 :                                 return -1;  // use all 1s to indicate wait for next RF-0 marker
     494              : 
     495            0 :                         if (!getNumber(opArguments_[1], value))
     496              :                         {
     497            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), for instruction '" << opArguments_[0] << ",' "
     498            0 :                                            << "the parameter value '" << opArguments_[1] << " " << opArguments_[2] << "' is not a valid number. "
     499            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     500            0 :                                 __SS_THROW__;
     501            0 :                         }
     502              :                         // test floating point in case integer conversion dropped something
     503            0 :                         double timeValue = strtod(opArguments_[1].c_str(), 0);
     504            0 :                         __COUTTV__(timeValue);
     505            0 :                         if (timeValue < value)
     506            0 :                                 timeValue = value;
     507              : 
     508            0 :                         __COUTTV__(FPGAClock_);
     509            0 :                         __COUTTV__(value);
     510            0 :                         __COUTTV__(timeValue);
     511              : 
     512            0 :                         if (opArguments_[2] == "s")  // Wait wanted in seconds
     513            0 :                                 return timeValue * 1e9 / FPGAClock_;
     514            0 :                         else if (opArguments_[2] == "ms")  // Wait wanted in milliseconds
     515            0 :                                 return timeValue * 1e6 / FPGAClock_;
     516            0 :                         else if (opArguments_[2] == "us")  // Wait wanted in microseconds
     517            0 :                                 return timeValue * 1e3 / FPGAClock_;
     518            0 :                         else if (opArguments_[2] == "ns")  // Wait wanted in nanoseconds
     519              :                         {
     520            0 :                                 if ((value % FPGAClock_) != 0)
     521              :                                 {
     522            0 :                                         __SS__ << "FPGA can only wait in multiples of " << FPGAClock_ << " ns: the input value '" << value << "' yields a remainder of " << (value % FPGAClock_) << __E__;
     523            0 :                                         __SS_THROW__;
     524            0 :                                 }
     525            0 :                                 return value / FPGAClock_;
     526              :                         }
     527            0 :                         else if (opArguments_[2] == "clocks")  // Wait wanted in FPGA clocks
     528            0 :                                 return value;
     529              :                         else  // impossible
     530              :                         {
     531            0 :                                 __SS__ << "WAIT command is missing unit type after parameter. Accepted unit types are clocks, ns, us, ms, and s." << __E__;
     532            0 :                                 __SS_THROW__;
     533            0 :                         }
     534              :                 }
     535            0 :                 case CFO_INSTR::LOOP:
     536            0 :                         if (opArgCount != 2)
     537              :                         {
     538            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 2 arguments, and " << opArgCount << " were found. Here is the syntax := \"" << opArguments_[0] << " [value]\" ... "
     539              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                   "The source instruction was \""
     540            0 :                                            << vectorToString(opArguments_, " " /*delimieter*/) << ".\"\n\n"
     541            0 :                                                                                                                                                           "For the loop count, hex 0x### and binary b### syntax is allowed, otherwise decimal is inferred."
     542            0 :                                            << __E__;
     543            0 :                                 __SS_THROW__;
     544            0 :                         }
     545            0 :                         if (!getNumber(opArguments_[1], value))
     546              :                         {
     547            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), for instruction '" << opArguments_[0] << ",' "
     548            0 :                                            << "the parameter value '" << opArguments_[1] << "' is not a valid number. "
     549            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     550            0 :                                 __SS_THROW__;
     551            0 :                         }
     552            0 :                         __COUTT__ << "loopStack_ = " << binLineNumber_ << " at " << loopStack_.size() << __E__;
     553            0 :                         loopStack_.push_back(binLineNumber_);
     554            0 :                         return value;
     555              : 
     556            0 :                 case CFO_INSTR::DO_LOOP:
     557            0 :                         if (opArgCount != 1)
     558              :                         {
     559            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", '" << opArguments_[0] << "' has extraneous arguments; there must be no additional arguments." << std::endl;
     560            0 :                                 __SS_THROW__;
     561            0 :                         }
     562            0 :                         if (!loopStack_.empty())
     563              :                         {
     564              :                                 uint64_t loopLine;
     565            0 :                                 loopLine = loopStack_.back();
     566            0 :                                 value = (binLineNumber_ - loopLine);
     567            0 :                                 __COUTT__ << "DO_LOOP from [" << binLineNumber_ << "], loop line popped = " << loopLine << ", must go back       " << value << " lines.";
     568            0 :                                 loopStack_.pop_back();
     569            0 :                                 __COUTT__ << "DO_LOOP loopStack_ " << loopStack_.size() << " w/parameterCalc=" << value;
     570            0 :                                 return value;
     571              :                         }
     572              :                         else
     573              :                         {
     574            0 :                                 __SS__ << "Identified at Line " << txtLineNumber_ << ", LOOP/DO_LOOP counts don't match. (There are more DO_LOOP's)";
     575            0 :                                 __SS_THROW__;
     576            0 :                         }
     577              :                         break;  // impossible to get here
     578            0 :                 case CFO_INSTR::REPEAT:
     579              :                 case CFO_INSTR::END:
     580            0 :                         if (opArgCount != 1)
     581              :                         {
     582            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", '" << opArguments_[0] << "' has extraneous arguments; there must be no additional arguments." << std::endl;
     583            0 :                                 __SS_THROW__;
     584            0 :                         }
     585            0 :                         if (!loopStack_.empty())  // loop stack must be empty at END or REPEAT
     586              :                         {
     587            0 :                                 __SS__ << "Identified at Line " << txtLineNumber_ << ", LOOP/DO_LOOP counts don't match (There are less DO_LOOP's)";
     588            0 :                                 __SS_THROW__;
     589            0 :                         }
     590            0 :                         break;
     591              : 
     592            0 :                 case CFO_INSTR::GOTO:
     593            0 :                         if (opArgCount != 1)
     594              :                         {
     595            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", '" << opArguments_[0] << "' has extraneous arguments; there must be no additional arguments." << std::endl;
     596            0 :                                 __SS_THROW__;
     597            0 :                         }
     598              : 
     599            0 :                         if (!loopStack_.empty())  // loop stack must be empty at GOTO
     600              :                         {
     601            0 :                                 __SS__ << "Identified at Line " << txtLineNumber_ << ", LOOP/DO_LOOP counts don't match (There are less DO_LOOP's); a GOTO can not be used to exit a loop.";
     602            0 :                                 __SS_THROW__;
     603            0 :                         }
     604            0 :                         opArguments_.push_back(MAIN_GOTO_LABEL);  // force label MAIN because only one GOTO ever makes sense if jumping in and out of loops is not allowed (since there are on IF statements)
     605            0 :                         opArguments_[1] = MAIN_GOTO_LABEL;        // in case of comments, push_back doesnt work
     606            0 :                         __COUTT__ << "Goto lookup label '" << opArguments_[1] << "'" << __E__;
     607              : 
     608            0 :                         if (labelMap_.find(opArguments_[1]) == labelMap_.end())
     609              :                         {
     610            0 :                                 for (auto& labelPair : labelMap_)
     611            0 :                                         __COUTTV__(labelPair.first);
     612            0 :                                 __SS__ << "Missing label '" << opArguments_[1] << "' needed for GOTO at line " << txtLineNumber_ << __E__;
     613            0 :                                 __SS_THROW__;
     614            0 :                         }
     615            0 :                         return labelMap_.at(opArguments_[1]);
     616              : 
     617            0 :                 case CFO_INSTR::LABEL:
     618            0 :                         if (opArgCount != 1)
     619              :                         {
     620            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", '" << opArguments_[0] << "' has extraneous arguments; there must be no additional arguments." << std::endl;
     621            0 :                                 __SS_THROW__;
     622            0 :                         }
     623              : 
     624            0 :                         if (!loopStack_.empty())  // loop stack must be empty at GOTO
     625              :                         {
     626            0 :                                 __SS__ << "Identified at Line " << txtLineNumber_ << ", LOOP/DO_LOOP counts don't match (There are less DO_LOOP's); a GOTO_LABEL can not be used to enter a loop.";
     627            0 :                                 __SS_THROW__;
     628            0 :                         }
     629              : 
     630              :                         // for now, leave label map in case if statements exist in the future, and more lables are allowed.
     631            0 :                         opArguments_.push_back(MAIN_GOTO_LABEL);
     632            0 :                         opArguments_[1] = MAIN_GOTO_LABEL;  // in case of comments, push_back doesnt work
     633              : 
     634            0 :                         __COUTT__ << "Saving map for label '" << opArguments_[1] << "' to line " << binLineNumber_ << __E__;
     635            0 :                         if (labelMap_.find(opArguments_[1]) != labelMap_.end())
     636              :                         {
     637            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", " << opArguments_[0] << " encountered when one already exists in the run plan. Only one " << opArguments_[0] << " allowed in a run plan." << __E__;
     638            0 :                                 __SS_THROW__;
     639            0 :                         }
     640            0 :                         labelMap_[opArguments_[1]] = binLineNumber_;
     641            0 :                         return 1;  // indicate MAIN LABEL to CFO firmware as valid location to dynamically switch run plans
     642              :                                            // otherwise, a normal noop label
     643            0 :                 case CFO_INSTR::SET_MODE_BITS:
     644              :                 case CFO_INSTR::AND_MODE_BITS:
     645              :                 case CFO_INSTR::OR_MODE_BITS:
     646              :                 case CFO_INSTR::OR_SINGLESHOT_MODE_BITS: {
     647            0 :                         if (opArgCount != 7 ||
     648            0 :                                 opArguments_[1] != "start_bit" ||
     649            0 :                                 opArguments_[3] != "bit_count" ||
     650            0 :                                 opArguments_[5] != "value")
     651              :                         {
     652            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 7 arguments, and " << opArgCount << " were found. Here is the syntax := \"" << opArguments_[0] << " start_bit=[value] bit_count=[value] value=[value]\" ... "
     653              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                   "The source instruction was \""
     654            0 :                                            << vectorToString(opArguments_, " " /*delimieter*/) << ".\"\n\n"
     655            0 :                                                                                                                                                           "For the number values, hex 0x### and binary b### syntax is allowed, otherwise decimal is inferred."
     656            0 :                                            << __E__;
     657            0 :                                 __SS_THROW__;
     658            0 :                         }
     659              : 
     660              :                         uint16_t startBit;
     661            0 :                         if (!getNumber(opArguments_[2], startBit))
     662              :                         {
     663            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), the "
     664            0 :                                            << "start_bit value '" << opArguments_[2] << "' is not a valid number. "
     665            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     666            0 :                                 __SS_THROW__;
     667            0 :                         }
     668              : 
     669            0 :                         if (startBit > 47)
     670              :                         {
     671            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), "
     672            0 :                                            << "start_bit value must be an integer between 0 and 47." << __E__;
     673            0 :                                 __SS_THROW__;
     674            0 :                         }
     675              : 
     676              :                         uint16_t bitCount;
     677            0 :                         if (!getNumber(opArguments_[4], bitCount))
     678              :                         {
     679            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), the "
     680            0 :                                            << "bit_count value '" << opArguments_[4] << "' is not a valid number. "
     681            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     682            0 :                                 __SS_THROW__;
     683            0 :                         }
     684              : 
     685            0 :                         if (startBit + bitCount > 48 || bitCount == 0)
     686              :                         {
     687            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), "
     688            0 :                                            << "bit_count value must be a positive integer and fit within 48-bits range 0-to-47 with offset start_bit=" << startBit << ". The end bit was calculated as end_bit=" << startBit + bitCount - 1 << __E__;
     689            0 :                                 __SS_THROW__;
     690            0 :                         }
     691              : 
     692            0 :                         if (!getNumber(opArguments_[6], value))
     693              :                         {
     694            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), the "
     695            0 :                                            << "bit_count value '" << opArguments_[6] << "' is not a valid number. "
     696            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     697            0 :                                 __SS_THROW__;
     698            0 :                         }
     699              : 
     700            0 :                         if (value >= (uint64_t(1) << bitCount) &&
     701            0 :                                 opArguments_[6][0] != '~')  // only if not an inverted value
     702              :                         {
     703            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), "
     704              :                                            << "the set value range is defined by bit_count, and so must be an integer between 0 and 2^"
     705            0 :                                            << "(bit_count=" << bitCount << ") - 1. The value is " << value << " which is greater than or equal to max range = " << (uint64_t(1) << bitCount) << __E__;
     706              :                                 ss << "\n\n"
     707            0 :                                    << "If an inverted value is intended, use '~' before the number to indicate inversion, and the value will be masked to fit within the bit_count range.";
     708            0 :                                 __SS_THROW__;
     709            0 :                         }
     710              : 
     711            0 :                         __COUTTV__(startBit);
     712            0 :                         __COUTTV__(bitCount);
     713            0 :                         __COUTTV__(value);
     714            0 :                         uint64_t bitmask = 0;
     715            0 :                         for (uint16_t i = startBit; i < startBit + bitCount; ++i)
     716            0 :                                 bitmask |= (uint64_t(1) << i);
     717              : 
     718            0 :                         switch (instructionOpcode)
     719              :                         {
     720            0 :                                 case CFO_INSTR::SET_MODE_BITS:  // treat SET_MODE_BITS as two ops in hardware: an AND and an OR
     721              : 
     722            0 :                                         __COUTT__ << "bitmask 0x" << std::hex << bitmask << __E__;
     723            0 :                                         value <<= startBit;         // shift then mask
     724            0 :                                         value &= bitmask;           // force bitcount in case of ~ inverted value
     725            0 :                                         modeClearMask_ = ~bitmask;  // CLEAR
     726            0 :                                         __COUTT__ << "modeClearMask_ 0x" << std::hex << modeClearMask_ << __E__;
     727            0 :                                         return value;  // SET
     728              : 
     729            0 :                                 case CFO_INSTR::AND_MODE_BITS:
     730              : 
     731            0 :                                         value <<= startBit;  // shift then mask
     732            0 :                                         value |= ~bitmask;   // force ignore outside of bitcount in case of ~ inverted value
     733            0 :                                         return value;        // AND
     734              : 
     735            0 :                                 case CFO_INSTR::OR_MODE_BITS:
     736              :                                 case CFO_INSTR::OR_SINGLESHOT_MODE_BITS:
     737              : 
     738            0 :                                         value <<= startBit;  // shift then mask
     739            0 :                                         value &= bitmask;    // force ignore outside of bitcount in case of ~ inverted value
     740            0 :                                         return value;        // OR / OR (single-shot)
     741              : 
     742            0 :                                 default: {
     743            0 :                                         __COUTTV__((int)instructionOpcode);
     744            0 :                                         __SS__ << "On Line " << txtLineNumber_ << ", invalid instruction '" << opArguments_[0] << "' encountered.'" << __E__;
     745            0 :                                         __SS_THROW__;
     746            0 :                                 }
     747              :                         }
     748              :                 }
     749            0 :                 case CFO_INSTR::CLEAR_MODE_BITS: {
     750            0 :                         if (opArgCount != 5 ||
     751            0 :                                 opArguments_[1] != "start_bit" ||
     752            0 :                                 opArguments_[3] != "bit_count")
     753              :                         {
     754            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 5 arguments, and " << opArgCount << " were found. Here is the syntax := \"" << opArguments_[0] << " start_bit=[value] bit_count=[value]\" ... "
     755              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                   "The source instruction was \""
     756            0 :                                            << vectorToString(opArguments_, " " /*delimieter*/) << ".\"\n\n"
     757            0 :                                                                                                                                                           "For the number values, hex 0x### and binary b### syntax is allowed, otherwise decimal is inferred."
     758            0 :                                            << __E__;
     759            0 :                                 __SS_THROW__;
     760            0 :                         }
     761              : 
     762              :                         uint16_t startBit;
     763            0 :                         if (!getNumber(opArguments_[2], startBit))
     764              :                         {
     765            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), the "
     766            0 :                                            << "start_bit value '" << opArguments_[2] << "' is not a valid number. "
     767            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     768            0 :                                 __SS_THROW__;
     769            0 :                         }
     770              : 
     771            0 :                         if (startBit > 47)
     772              :                         {
     773            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), "
     774            0 :                                            << "start_bit value must be an integer between 0 and 47." << __E__;
     775            0 :                                 __SS_THROW__;
     776            0 :                         }
     777              : 
     778              :                         uint16_t bitCount;
     779            0 :                         if (!getNumber(opArguments_[4], bitCount))
     780              :                         {
     781            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), the "
     782            0 :                                            << "bit_count value '" << opArguments_[4] << "' is not a valid number. "
     783            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     784            0 :                                 __SS_THROW__;
     785            0 :                         }
     786              : 
     787            0 :                         if (startBit + bitCount > 48 || bitCount == 0)
     788              :                         {
     789            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), "
     790            0 :                                            << "bit_count value must be a positive integer and fit within 48-bits range 0:47 with offset start_bit=" << startBit << ". The end bit was calculated as end_bit=" << startBit + bitCount - 1 << __E__;
     791            0 :                                 __SS_THROW__;
     792            0 :                         }
     793              : 
     794            0 :                         uint64_t bitmask = 0;
     795            0 :                         for (uint16_t i = startBit; i < startBit + bitCount; ++i)
     796            0 :                                 bitmask |= (uint64_t(1) << i);
     797            0 :                         return ~bitmask;  // CLEAR
     798              :                 }
     799            0 :                 case CFO_INSTR::SET_MODE:  // treat SET_MODE as two ops in hardware: an AND and an OR
     800              :                 {
     801            0 :                         if (opArgCount != 2)
     802              :                         {
     803            0 :                                 __SS__ << "On Line " << txtLineNumber_ << ", invalid '" << opArguments_[0] << "' arguments found. There must be 5 arguments, and " << opArgCount << " were found. Here is the syntax := \"" << opArguments_[0] << " [value]\" ... "
     804              :                                                                                                                                                                                                                                                                                                                                                                                                                                                                   "The source instruction was \""
     805            0 :                                            << vectorToString(opArguments_, " " /*delimieter*/) << ".\"\n\n"
     806            0 :                                                                                                                                                           "For the Event Mode value, hex 0x### and binary b### syntax is allowed, otherwise decimal is inferred."
     807            0 :                                            << __E__;
     808            0 :                                 __SS_THROW__;
     809            0 :                         }
     810              : 
     811            0 :                         if (!getNumber(opArguments_[1], value))
     812              :                         {
     813            0 :                                 __SS__ << "On Line (" << txtLineNumber_ << "), the "
     814            0 :                                            << "start_bit value '" << opArguments_[1] << "' is not a valid number. "
     815            0 :                                            << "Use 0x### to indicate hex and b### to indicate binary; otherwise, decimal is inferred." << __E__;
     816            0 :                                 __SS_THROW__;
     817            0 :                         }
     818              : 
     819              :                         // treat SET_MODE as two ops in hardware: an AND and an OR
     820            0 :                         modeClearMask_ = 0;  // CLEAR
     821            0 :                         return value;        // SET
     822              :                 }
     823            0 :                 default: {
     824            0 :                         __COUTTV__((int)instructionOpcode);
     825            0 :                         __SS__ << "On Line " << txtLineNumber_ << ", invalid instruction '" << opArguments_[0] << "' encountered.'" << __E__;
     826            0 :                         __SS_THROW__;
     827            0 :                 }
     828              :         }  // end primary switch statement
     829              : 
     830            0 :         return 0;  // default parameter value
     831              : }  // end calculateParameterAndErrorCheck()
     832              : 
     833              : //==============================================================================
     834              : // static template function (copied from ots::StringMacros)
     835              : //      for all numbers, but not bools (bools has a specialized template definition)
     836              : //      return false if string is not a number
     837              : template<class T>
     838            0 : bool getNumber(const std::string& s, T& retValue)
     839              : {
     840            0 :         __COUTVS__(2, s);
     841              : 
     842              :         // extract set of potential numbers and operators
     843            0 :         std::vector<std::string> numbers;
     844            0 :         std::vector<char> ops;
     845              : 
     846            0 :         getVectorFromString(s,
     847              :                                                 numbers,
     848            0 :                                                 /*delimiter*/ std::set<char>({'+', '-', '*', '/', '~'}),
     849            0 :                                                 /*whitespace*/ std::set<char>({' ', '\t', '\n', '\r'}),
     850              :                                                 &ops);
     851              : 
     852            0 :         __COUTVS__(2, vectorToString(numbers));
     853            0 :         __COUTVS__(2, vectorToString(ops));
     854              : 
     855            0 :         retValue = 0;  // initialize
     856              : 
     857              :         T tmpValue;
     858              : 
     859            0 :         unsigned int i = 0;
     860            0 :         unsigned int opsi = 0;
     861            0 :         unsigned int blankNumberCount = 0;
     862              :         bool verified;
     863            0 :         for (const auto& number : numbers)
     864              :         {
     865            0 :                 if (number.size() == 0)
     866              :                 {
     867            0 :                         ++blankNumberCount;
     868            0 :                         continue;  // skip empty numbers
     869              :                 }
     870              : 
     871              :                 // verify that this number looks like a number
     872              :                 //      for integer types, allow hex and binary
     873              :                 //      for all types allow base10
     874              : 
     875            0 :                 verified = false;
     876              : 
     877            0 :                 __COUTVS__(2, number);
     878              : 
     879              :                 // check integer types
     880            0 :                 if (typeid(unsigned int) == typeid(retValue) || typeid(int) == typeid(retValue) || typeid(unsigned long long) == typeid(retValue) ||
     881            0 :                         typeid(long long) == typeid(retValue) || typeid(unsigned long) == typeid(retValue) || typeid(long) == typeid(retValue) ||
     882            0 :                         typeid(unsigned short) == typeid(retValue) || typeid(short) == typeid(retValue) || typeid(uint8_t) == typeid(retValue))
     883              :                 {
     884            0 :                         if (number.find("0x") == 0)  // indicates hex
     885              :                         {
     886            0 :                                 __COUTS__(2) << "0x found" << __E__;
     887            0 :                                 for (unsigned int i = 2; i < number.size(); ++i)
     888              :                                 {
     889            0 :                                         if (!((number[i] >= '0' && number[i] <= '9') || (number[i] >= 'A' && number[i] <= 'F') || (number[i] >= 'a' && number[i] <= 'f')))
     890              :                                         {
     891            0 :                                                 __COUT__ << "prob " << number[i] << __E__;
     892            0 :                                                 return false;
     893              :                                         }
     894              :                                 }
     895            0 :                                 verified = true;
     896              :                         }
     897            0 :                         else if (number[0] == 'b')  // indicates binary
     898              :                         {
     899            0 :                                 __COUTS__(2) << "b found" << __E__;
     900              : 
     901            0 :                                 for (unsigned int i = 1; i < number.size(); ++i)
     902              :                                 {
     903            0 :                                         if (!((number[i] >= '0' && number[i] <= '1')))
     904              :                                         {
     905            0 :                                                 __COUT__ << "prob " << number[i] << __E__;
     906            0 :                                                 return false;
     907              :                                         }
     908              :                                 }
     909            0 :                                 verified = true;
     910              :                         }
     911              :                 }
     912              : 
     913              :                 // if not verified above, for all types, check base10
     914            0 :                 if (!verified)
     915            0 :                         for (unsigned int i = 0; i < number.size(); ++i)
     916            0 :                                 if (!((number[i] >= '0' && number[i] <= '9') || number[i] == '.' || number[i] == '+' || number[i] == '-'))
     917            0 :                                         return false;
     918              : 
     919              :                 // at this point, this number is confirmed to be a number of some sort
     920              :                 // so convert to temporary number
     921            0 :                 if (typeid(double) == typeid(retValue))
     922            0 :                         tmpValue = strtod(number.c_str(), 0);
     923            0 :                 else if (typeid(float) == typeid(retValue))
     924            0 :                         tmpValue = strtof(number.c_str(), 0);
     925            0 :                 else if (typeid(unsigned int) == typeid(retValue) || typeid(int) == typeid(retValue) || typeid(unsigned long long) == typeid(retValue) ||
     926            0 :                                  typeid(long long) == typeid(retValue) || typeid(unsigned long) == typeid(retValue) || typeid(long) == typeid(retValue) ||
     927            0 :                                  typeid(unsigned short) == typeid(retValue) || typeid(short) == typeid(retValue) || typeid(uint8_t) == typeid(retValue))
     928              :                 {
     929            0 :                         __COUTVS__(2, number);
     930            0 :                         if (number.size() > 2 && number[1] == 'x')  // assume hex value
     931            0 :                                 tmpValue = (T)strtol(number.c_str(), 0, 16);
     932            0 :                         else if (number.size() > 1 && number[0] == 'b')            // assume binary value
     933            0 :                                 tmpValue = (T)strtol(number.substr(1).c_str(), 0, 2);  // skip first 'b' character
     934              :                         else
     935            0 :                                 tmpValue = (T)strtol(number.c_str(), 0, 10);
     936              :                 }
     937              :                 else  // just try!
     938              :                 {
     939            0 :                         __COUTVS__(2, number);
     940            0 :                         if (number.size() > 2 && number[1] == 'x')  // assume hex value
     941            0 :                                 tmpValue = (T)strtol(number.c_str(), 0, 16);
     942            0 :                         else if (number.size() > 1 && number[0] == 'b')            // assume binary value
     943            0 :                                 tmpValue = (T)strtol(number.substr(1).c_str(), 0, 2);  // skip first 'b' character
     944              :                         else
     945            0 :                                 tmpValue = (T)strtol(number.c_str(), 0, 10);
     946              :                         // __SS__ << "Invalid type '" << StringMacros::demangleTypeName(typeid(retValue).name()) << "' requested for a numeric string. Data was '" << number
     947              :                         //        << "'" << __E__;
     948              :                         // __SS_THROW__;
     949              :                 }
     950              : 
     951            0 :                 __COUTVS__(2, tmpValue);
     952              : 
     953              :                 // apply operation
     954            0 :                 if (i == 0)  // first value, no operation, just take value
     955              :                 {
     956            0 :                         retValue = tmpValue;
     957              : 
     958            0 :                         if (ops.size() == numbers.size() - blankNumberCount)  // then there is a leading operation, so apply
     959              :                         {
     960            0 :                                 if (ops[opsi] == '-')  // only meaningful op is negative sign
     961            0 :                                         retValue *= -1;
     962            0 :                                 else if (ops[opsi] == '~')  // handle bit invert
     963            0 :                                         retValue = ~tmpValue;
     964            0 :                                 __COUTT__ << "Op " << (ops.size() ? ops[opsi] : '_') << " intermediate value = " << std::dec << retValue << " 0x" << std::hex << retValue << __E__;
     965            0 :                                 opsi++;  // jump to first internal op
     966              :                         }
     967              :                 }
     968              :                 else  // there is some sort of op
     969              :                 {
     970              :                         if (0 && i == 1)  // display what we are dealing with
     971              :                         {
     972              :                                 __COUTTV__(vectorToString(numbers));
     973              :                                 __COUTTV__(vectorToString(ops));
     974              :                         }
     975            0 :                         __COUTTV__(opsi);
     976            0 :                         __COUTTV__(ops[opsi]);
     977            0 :                         __COUTTV__(tmpValue);
     978            0 :                         __COUTT__ << "Intermediate value = " << std::dec << retValue << " 0x" << std::hex << retValue << __E__;
     979              : 
     980            0 :                         switch (ops[opsi])
     981              :                         {
     982            0 :                                 case '+':
     983            0 :                                         retValue += tmpValue;
     984            0 :                                         break;
     985            0 :                                 case '-':
     986            0 :                                         retValue -= tmpValue;
     987            0 :                                         break;
     988            0 :                                 case '*':
     989            0 :                                         retValue *= tmpValue;
     990            0 :                                         break;
     991            0 :                                 case '/':
     992            0 :                                         retValue /= tmpValue;
     993            0 :                                         break;
     994            0 :                                 default:
     995            0 :                                         __SS__ << "Unrecognized operation '" << ops[opsi] << "' found!" << __E__ << "Numbers: " << vectorToString(numbers) << __E__
     996            0 :                                                    << "Operations: " << vectorToString(ops) << __E__;
     997            0 :                                         __SS_THROW__;
     998            0 :                         }
     999              : 
    1000            0 :                         __COUTT__ << "Op " << (ops.size() ? ops[opsi] : '_') << " intermediate value = " << std::dec << retValue << " 0x" << std::hex << retValue << __E__;
    1001            0 :                         ++opsi;
    1002              :                 }
    1003            0 :                 __COUTT__ << i << ": Op intermediate value = " << std::dec << retValue << " 0x" << std::hex << retValue << __E__;
    1004              : 
    1005            0 :                 ++i;  // increment index for next number/op
    1006              : 
    1007              :         }  // end number loop
    1008              : 
    1009            0 :         return true;  // number was valid and is passed by reference in retValue
    1010            0 : }  // end static getNumber<T>()
    1011              : 
    1012              : //==============================================================================
    1013              : // getVectorFromString (copied from ots::StringMacros)
    1014              : //      extracts the list of elements from string that uses a delimiter
    1015              : //              ignoring whitespace
    1016              : //      optionally returns the list of delimiters encountered, which may be useful
    1017              : //              for extracting which operator was used.
    1018              : //
    1019              : //
    1020              : //      Note: lists are returned as vectors
    1021              : //      Note: the size() of delimiters will be one less than the size() of the returned values
    1022              : //              unless there is a leading delimiter, in which case vectors will have the same
    1023              : // size.
    1024            0 : void getVectorFromString(const std::string& inputString,
    1025              :                                                  std::vector<std::string>& listToReturn,
    1026              :                                                  const std::set<char>& delimiter,
    1027              :                                                  const std::set<char>& whitespace,
    1028              :                                                  std::vector<char>* listOfDelimiters
    1029              :                                                  /* dont care about URI in compiler ,
    1030              :                                                  bool                      decodeURIComponents */
    1031              : )
    1032              : {
    1033            0 :         unsigned int i = 0;
    1034            0 :         unsigned int j = 0;
    1035            0 :         unsigned int c = 0;
    1036            0 :         std::set<char>::iterator delimeterSearchIt;
    1037            0 :         char lastDelimiter = 0;
    1038              :         bool isDelimiter;
    1039              :         // bool foundLeadingDelimiter = false;
    1040              : 
    1041              :         // __COUT__ << inputString << __E__;
    1042              :         // __COUTV__(inputString.length());
    1043              : 
    1044              :         // go through the full string extracting elements
    1045              :         // add each found element to set
    1046            0 :         for (; c < inputString.size(); ++c)
    1047              :         {
    1048              :                 // __COUT__ << (char)inputString[c] << __E__;
    1049              : 
    1050            0 :                 delimeterSearchIt = delimiter.find(inputString[c]);
    1051            0 :                 isDelimiter = delimeterSearchIt != delimiter.end();
    1052              : 
    1053              :                 // __COUT__ << (char)inputString[c] << " " << isDelimiter << __E__;
    1054              : 
    1055            0 :                 if (whitespace.find(inputString[c]) != whitespace.end()  // ignore leading white space
    1056            0 :                         && i == j)
    1057              :                 {
    1058            0 :                         ++i;
    1059            0 :                         ++j;
    1060              :                         // if(isDelimiter)
    1061              :                         //      foundLeadingDelimiter = true;
    1062              :                 }
    1063            0 :                 else if (whitespace.find(inputString[c]) != whitespace.end() && i != j)  // trailing white space, assume possible end of element
    1064              :                 {
    1065              :                         // do not change j or i
    1066              :                 }
    1067            0 :                 else if (isDelimiter)  // delimiter is end of element
    1068              :                 {
    1069              :                         // __COUT__ << "Set element found: " <<
    1070              :                         //              inputString.substr(i,j-i) << " sz=" << inputString.substr(i,j-i).length() << std::endl;
    1071              : 
    1072            0 :                         if (listOfDelimiters && listToReturn.size())  // || foundLeadingDelimiter))
    1073              :                                                                                                                   // //accept leading delimiter
    1074              :                                                                                                                   // (especially for case of
    1075              :                                                                                                                   // leading negative in math
    1076              :                                                                                                                   // parsing)
    1077              :                         {
    1078              :                                 //__COUTV__(lastDelimiter);
    1079            0 :                                 listOfDelimiters->push_back(lastDelimiter);
    1080              :                         }
    1081            0 :                         listToReturn.push_back(  // decodeURIComponents ? StringMacros::decodeURIComponent(inputString.substr(i, j - i)) :
    1082            0 :                                 inputString.substr(i, j - i));
    1083              : 
    1084              :                         // setup i and j for next find
    1085            0 :                         i = c + 1;
    1086            0 :                         j = c + 1;
    1087              :                 }
    1088              :                 else  // part of element, so move j, not i
    1089            0 :                         j = c + 1;
    1090              : 
    1091            0 :                 if (isDelimiter)
    1092            0 :                         lastDelimiter = *delimeterSearchIt;
    1093              :                 //__COUTV__(lastDelimiter);
    1094              :         }
    1095              : 
    1096              :         if (1)  // i != j) //last element check (for case when no concluding ' ' or delimiter)
    1097              :         {
    1098              :                 // __COUT__ << "Last element found: " <<
    1099              :                 //              inputString.substr(i,j-i) << std::endl;
    1100              : 
    1101            0 :                 if (listOfDelimiters && listToReturn.size())  // || foundLeadingDelimiter))
    1102              :                                                                                                           // //accept leading delimiter
    1103              :                                                                                                           // (especially for case of leading
    1104              :                                                                                                           // negative in math parsing)
    1105              :                 {
    1106              :                         //__COUTV__(lastDelimiter);
    1107            0 :                         listOfDelimiters->push_back(lastDelimiter);
    1108              :                 }
    1109            0 :                 listToReturn.push_back(  // decodeURIComponents ? StringMacros::decodeURIComponent(inputString.substr(i, j - i)) :
    1110            0 :                         inputString.substr(i, j - i));
    1111              :         }
    1112              : 
    1113              :         // assert that there is one less delimiter than values
    1114            0 :         if (listOfDelimiters && listToReturn.size() - 1 != listOfDelimiters->size() && listToReturn.size() != listOfDelimiters->size())
    1115              :         {
    1116            0 :                 __SS__ << "There is a mismatch in delimiters to entries (should be equal or one "
    1117            0 :                                   "less delimiter): "
    1118            0 :                            << listOfDelimiters->size() << " vs " << listToReturn.size() << __E__ << "Entries: " << vectorToString(listToReturn) << __E__
    1119            0 :                            << "Delimiters: " << vectorToString(*listOfDelimiters) << __E__;
    1120            0 :                 __SS_THROW__;
    1121            0 :         }
    1122              : 
    1123            0 : }  // end getVectorFromString()
    1124              : 
    1125              : //==============================================================================
    1126              : // static template function (copied from ots::StringMacros)
    1127              : template<class T>
    1128            0 : std::string vectorToString(const std::vector<T>& setToReturn, const std::string& delimeter /*= ", "*/)
    1129              : {
    1130            0 :         std::stringstream ss;
    1131            0 :         bool first = true;
    1132            0 :         for (auto& setValue : setToReturn)
    1133              :         {
    1134            0 :                 if (first)
    1135            0 :                         first = false;
    1136              :                 else
    1137            0 :                         ss << delimeter;
    1138            0 :                 ss << setValue;
    1139              :         }
    1140            0 :         return ss.str();
    1141            0 : }  // end vectorToString<T>()
        

Generated by: LCOV version 2.0-1