iota-machine
iota-machine.h
Go to the documentation of this file.
00001 /*
00002  * iota-machine.h - interface for the Iota little language simulator
00003  *
00004  * Copyright 2012 David R. Miller
00005  *
00006  * This file is part of the Iota little language simulator.
00007  *
00008  * Iota is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 3 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * Iota is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Iota.  If not, see <http://www.gnu.org/licenses/>.
00020  *
00021  * Contact: http://www.millermattson.com/dave
00022  */
00023 
00036 #ifndef IOTA_MACHINE_H
00037 #define IOTA_MACHINE_H
00038 
00039 #include <cstdlib>
00040 #include <ctime>
00041 #include <iomanip>
00042 #include <iostream>
00043 #include <stdexcept>
00044 #include <string>
00045 #include <vector>
00046 
00047 
00052 namespace iota {
00053 
00054     static const std::string languageVersion { "Iota language version 1.0" };
00055     static const std::string simulatorVersion { "Iota simulator version 1.0" };
00056 
00061     class iotaExcept : public std::runtime_error {
00062     public:
00063         iotaExcept() : std::runtime_error("Can't construct an iota::machine object (check the ctor args)") { }
00064     };
00065 
00073     template <typename T>
00074     class machine
00075     {
00076     public:  // functions
00078         typedef T value_type;
00079 
00081         machine(size_t archLength, size_t archWidth = 8);
00082 
00084         void reset(void);
00085 
00087         void copyProgramToMachineMemory(const std::string &src);
00088 
00090         void setDataInputSource(const std::string &dataInSource);
00091 
00093         void setDebugLevel(int level);
00094 
00096         void setExecutionTrace(int level);
00097 
00099         std::string listProgramShortMnemonics(size_t maxLength = 0) const;
00100 
00102         void sprintState(void) const;
00103 
00105         void disassemble(void) const;
00106 
00108         size_t executeAtMost(size_t numberOfCycles);
00109 
00111         bool executeOneCycle(void);
00112 
00113     public: // directly accessible data
00121         std::string mOutputStream;     // destination for OUT opcode
00122 
00124         const size_t maxOutputStreamSize = 128*1024; // some reasonably big limit
00125 
00132         std::string allOpcodeChars;   // a generated set of all defined short mnemonics
00133 
00138         enum opcodeNumber {
00139             OP_NOP,     // (0) No-operation, do-nothing
00140             OP_RESET,   // Reset the virtual machine
00141             OP_HALT,    // Halt Iota program execution
00142             OP_IN,      // Input a char from stdin, push it onto the stack
00143             OP_OUT,     // Pop a word from the stack, output to stdout
00144             OP_POP,     // Pop a word from the stack
00145             OP_DUP,     // Duplicate the last stacked value
00146             OP_PUSHPC,  // Push the PC onto the stack
00147             OP_POPPC,   // Pop the PC from the stack
00148             OP_POPSP,   // Pop the SP from the stack
00149             OP_SPTGT,   // (10) Set the SP to the next TARGET opcode
00150             OP_PUSHNZ,  // Push the NZ flag
00151             OP_SWAP,    // Swap the top two items on the stack
00152             OP_PUSH0,   // Push a zero onto the stack
00153             OP_ADD,     // Add the top two stacked words, push the result
00154             OP_SUB,     // Subtract the top two stacked words and push the result
00155             OP_INC,     // Increment the item at the top of the stack
00156             OP_DEC,     // Decrement the item on the top of the stack
00157             OP_MUL,     // Multiply the top two stacked words and push the result
00158             OP_DIV,     // Pop two words, divide, push the quotient and remainder
00159             OP_XOR,     // (20) Bitwise XOR the top two stacked words and push the result
00160             OP_AND,     // Bitwise AND the top two stacked words and push the result
00161             OP_OR,      // Bitwise OR the top two stacked words and push the result
00162             OP_SHL,     // Logical shift left the top stacked word
00163             OP_SHR,     // Logical shift right the top stacked word
00164             OP_NOT,     // Bitwise NOT the top stacked word
00165             OP_BZ,      // Branch if zero (NZ flag is false)
00166             OP_BNZ,     // Branch if nonzero (NZ flag is true)
00167             OP_BEQ,     // Compare top two stacked words, branch if equal
00168             OP_BGT,     // Compare top two stacked words, branch if greater than
00169             OP_BLT,     // (30) Compare top two stacked words, branch if less than
00170             OP_BGE,     // Compare top two stacked words, branch if greater than or equal
00171             OP_LOOP,    // Repeat the following instructions up to the next std::endl
00172             OP_ENDL,    // End of LOOP
00173             OP_BRAN,    // Branch to the next TARGET opcode
00174             OP_BRAP,    // Branch to the previous TARGET opcode
00175             OP_TARGET,  // Branch target for BRAN and BRAP
00176             OP_SKIP1,   // Skip one instruction
00177             OP_SKIP2,   // Skip the next two instructions
00178             OP_SKIP3,   // Skip the next three instructions
00179             OP_SKIP4,   // (40) Skip the next four instructions
00180             OP_SKIP5,   // Skip the next five instructions
00181             OP_SKIP6,   // Skip the next six instructions
00182             OP_SKIP7,   // Skip the next seven instructions
00183             OP_SKIP8,   // Skip the next eight instructions
00184             OP_SKIP9,   // (45) Skip the next nine instructions
00185             NUMBER_OF_OPCODES   // (46)
00186         };
00187 
00188         // *************************** under the covers ***************************
00189 
00190     private: // private types and data
00191         size_t mArchLength;             // simulated memory length [1..2^32)
00192         size_t mArchWidth;              // simulated memory width in bits [6..32)
00193         unsigned long mCycleNumber;     // number of Iota cycles executed
00194         size_t pc;                      // program counter
00195         size_t sp;                      // stack pointer
00196         bool   nz;                      // non-zero flag; true means non-zero
00197         std::string mDataIn;            // source of input data for IN opcode
00198         size_t mDataInIdx;              // index into dataIn
00199         int mExecutionTraceLevel;       // 0=no trace listing; >0 = trace listing
00200         int mDebugLevel;                // zero is silent; nonzero is extra debug output
00201         std::vector<T> mem;             // Iota simulated memory, archLength x archWidth
00202 
00203         struct opcodeDetails
00204         {
00205             enum opcodeNumber num;      // the opcode number, [0..NUMBER_OF_OPCODES)
00206             char shortMnemonic;         // the short opcode mnemonic, e.g, 'H'
00207             const char *longMnemonic;   // the long opcode mnemonic, e.g., "HALT"
00208         };
00209 
00210         // For performance reasons, it's important to have a constant-time
00211         // lookup tables by number and by char value. Since the tables are
00212         // so small and simple, we'll just build the two lookup tables at
00213         // runtime using the data in mOpcodeTable[] as input.
00214 
00215         static const opcodeDetails mOpcodeTable[NUMBER_OF_OPCODES];   // input, human-maintainable
00216         opcodeDetails mOpcodeTableByNumber[NUMBER_OF_OPCODES];        // generated at runtime
00217         opcodeDetails mOpcodeTableByCharacter[256];                   // generated at runtime
00218 
00219     private: // private functions
00220         // Wrap an address to the actual number of memory locations:
00221         inline T wrap(T a) { return a % mArchLength; }
00222 
00223         // Truncate a number to the machine word width:
00224         inline T trunc(T val) { return val & ((1UL << mArchWidth) - 1); }
00225 
00226         // Helpers for PC and SP arithmetic:
00227         inline void setnz(T val) { nz = !!val; }
00228         inline void decsp(void) { sp = sp == 0 ? mArchLength - 1 : sp - 1; }
00229         inline void incsp(void) { sp = (sp + 1) % mArchLength; }
00230         inline void incpc(void) { pc = (pc + 1) % mArchLength; }
00231 
00232         // create opcodeTableByNumber and opcodeTableByCharacter from mOpcodeTable
00233         void initOpcodeTables(void);
00234 
00235         // Given an opcode number, return its details. If the number is
00236         // not a valid opcode number, return the details for the NOP opcode.
00237         const opcodeDetails& findByNumber(size_t n) const;
00238 
00239         // Given an opcode single-character mnemonic. return its
00240         // details. If the char is not a valid opcode mnemonic, return
00241         // the details as if it were a NOP opcode.
00242         const opcodeDetails& findByShortMnemonic(char c) const;
00243     };
00244 
00245 
00246     // ****************************** Implementation ******************************
00247 
00248 
00255     template <typename T>
00256     const typename machine<T>::opcodeDetails machine<T>::mOpcodeTable[NUMBER_OF_OPCODES] = {
00257         { OP_NOP,    ';', "NOP" },
00258         { OP_RESET,  'R', "RESET" },
00259         { OP_HALT,   'H', "HALT" },
00260         { OP_IN,     'I', "IN" },
00261         { OP_OUT,    'O', "OUT" },
00262         { OP_POP,    'p', "POP" },
00263         { OP_DUP,    'D', "DUP" },
00264         { OP_PUSHPC, 'C', "PUSHPC" },
00265         { OP_POPPC,  'c', "POPPC" },
00266         { OP_POPSP,  'Y', "POPSP" },
00267         { OP_SPTGT,  'G', "SPTGT" },
00268         { OP_PUSHNZ, 'P', "PUSHNZ" },
00269         { OP_SWAP,   'S', "SWAP" },
00270         { OP_PUSH0,  '0', "PUSH0" },
00271         { OP_ADD,    '+', "ADD" },
00272         { OP_SUB,    '-', "SUB" },
00273         { OP_INC,    '.', "INC" },
00274         { OP_DEC,    ',', "DEC" },
00275         { OP_MUL,    '*', "MUL" },
00276         { OP_DIV,    '/', "DIV" },
00277         { OP_XOR,    '^', "XOR" },
00278         { OP_AND,    '&', "AND" },
00279         { OP_OR,     '|', "OR" },
00280         { OP_SHL,    '(', "SHL" },
00281         { OP_SHR,    ')', "SHR" },
00282         { OP_NOT,    '~', "NOT" },
00283         { OP_BZ,     'Z', "BZ" },
00284         { OP_BNZ,    'z', "BNZ" },
00285         { OP_BEQ,    '=', "BEQ" },
00286         { OP_BGT,    '>', "BGT" },
00287         { OP_BLT,    '{', "BLT" },
00288         { OP_BGE,    '}', "BGE" },
00289         { OP_LOOP,   'L', "LOOP" },
00290         { OP_ENDL,   ']', "ENDL" },
00291         { OP_BRAN,   'B', "BRAN" },
00292         { OP_BRAP,   'b', "BRAP" },
00293         { OP_TARGET, 'T', "TARGET" },
00294         { OP_SKIP1,  '1', "SKIP1" },
00295         { OP_SKIP2,  '2', "SKIP2" },
00296         { OP_SKIP3,  '3', "SKIP3" },
00297         { OP_SKIP4,  '4', "SKIP4" },
00298         { OP_SKIP5,  '5', "SKIP5" },
00299         { OP_SKIP6,  '6', "SKIP6" },
00300         { OP_SKIP7,  '7', "SKIP7" },
00301         { OP_SKIP8,  '8', "SKIP8" },
00302         { OP_SKIP9,  '9', "SKIP9" }
00303     };
00304 
00314     template <typename T>
00315     machine<T>::machine(size_t archLength, size_t archWidth)
00316         : mOutputStream(std::string()), mArchLength(archLength), mArchWidth(archWidth),
00317           mCycleNumber(0), pc(0), sp(0), nz(0), mDataIn(std::string()), mDataInIdx(0),
00318           mExecutionTraceLevel(0), mDebugLevel(0), mem(std::vector<T>(archLength, 0))
00319     {
00320         // check ranges
00321         if (mArchWidth < 6 || mArchWidth > 32) {
00322             std::cerr << "Oops: archWidth must be in the range [6..32]" << std::endl;
00323             throw iotaExcept();
00324             exit(1);
00325         }
00326 
00327         if (mArchLength < 1) {
00328             std::cerr << "Oops: archLength must be in the range [1..2^32]" << std::endl;
00329             throw iotaExcept();
00330             exit(1);
00331         }
00332 
00333         initOpcodeTables();
00334     }
00335 
00342     template <typename T>
00343     void machine<T>::reset(void)
00344     {
00345         pc = 0;
00346         sp = 0;
00347         nz = 0;
00348         mCycleNumber = 0;
00349         mOutputStream = std::string();
00350         mDataInIdx = 0;
00351         fill(begin(mem), end(mem), OP_NOP);
00352     }
00353 
00364     template <typename T>
00365     void machine<T>::copyProgramToMachineMemory(const std::string &src)
00366     {
00367         if (src.size() == 0) {
00368             mem[0] = OP_NOP;
00369             return;
00370         }
00371 
00372         size_t loc = 0;
00373         for (auto it = src.begin(); loc < mArchLength && it != src.end(); ++loc, ++it) {
00374             // get and store the opcode number or the literal char value if not an opcode
00375             mem[loc] = (T)findByShortMnemonic(*it).num;
00376         }
00377     }
00378 
00389     template <typename T>
00390     void machine<T>::setDataInputSource(const std::string &dataInSource)
00391     {
00392         mDataIn = dataInSource;
00393         mDataInIdx = 0;
00394     }
00395 
00401     template <typename T>
00402     void machine<T>::setDebugLevel(int level)
00403     {
00404         mDebugLevel = level;
00405     }
00406 
00412     template <typename T>
00413     void machine<T>::setExecutionTrace(int level)
00414     {
00415         mExecutionTraceLevel = level;
00416     }
00417 
00428     template <typename T>
00429     std::string machine<T>::listProgramShortMnemonics(size_t maxLength) const
00430     {
00431         std::string program { "" };
00432 
00433         if (maxLength == 0) {
00434             maxLength = mArchLength;
00435         }
00436 
00437         for (size_t i = 0; i < maxLength; ++i) {
00438             size_t n = (size_t)mem[i];
00439             if (n < NUMBER_OF_OPCODES) {
00440                 program += findByNumber(mem[i]).shortMnemonic;
00441             } else if (n <= 0xff) {
00442                 // show the literal character
00443                 program += (char)n;
00444             } else {
00445                 program += findByNumber(OP_NOP).shortMnemonic; // i.e., ';'
00446             }
00447         }
00448 
00449         return program;
00450     }
00451 
00456     template <typename T>
00457     void machine<T>::sprintState(void) const
00458     {
00459         unsigned hexWidth = (mArchWidth - 1) / 4 + 1;
00460 
00461         std::cerr << "T"
00462              << std::setw(8) << std::dec << std::setfill('0') << mCycleNumber << ": "
00463              << "PC=" << std::setw(hexWidth) << std::hex << std::setfill('0') << pc << " "
00464              << "SP=" << std::setw(hexWidth) << std::hex << std::setfill('0') << sp << " "
00465              << "NZ=" << (nz ? 'T' : 'F') << " mem[]=";
00466 
00467         for (auto i : mem) {
00468             std::cerr << std::setw(hexWidth) << std::hex << std::setfill('0') << (size_t)i << " ";
00469         }
00470 
00471         std::cerr << std::endl
00472              << std::setw(hexWidth) << std::hex << std::setfill('0') << (size_t)pc << ": "
00473              << std::setw(hexWidth) << std::hex << std::setfill('0') << (size_t)mem[pc] << " "
00474              << findByNumber(mem[pc]).shortMnemonic << " "
00475              << findByNumber(mem[pc]).longMnemonic << " "
00476              << std::endl;
00477     }
00478 
00483     template <typename T>
00484     void machine<T>::disassemble(void) const
00485     {
00486         std::cerr << "Memory dump/disasm:" << std::endl;
00487 
00488         for (size_t i = 0; i < mem.size(); ++i) {
00489             std::cerr << std::setw(3) << std::hex << std::setfill(' ') << i << " "
00490                  << std::setw(2) << std::hex << std::setfill('0') << (size_t)mem[i] << " ";
00491             size_t n = mem[i];
00492             if (n < NUMBER_OF_OPCODES) {
00493                 std::cerr << findByNumber((size_t)n).shortMnemonic << " "
00494                      << findByNumber((size_t)n).longMnemonic;
00495             } else if (n <= 0xff) {
00496                 std::cerr << "  \'" << (char)n << "\' (NOP)";
00497             } else {
00498                 std::cerr << std::hex << n;
00499             }
00500 
00501             std::cerr << std::endl;
00502         }
00503     }
00504 
00513     template <typename T>
00514     size_t machine<T>::executeAtMost(size_t numberOfCycles)
00515     {
00516         if (mExecutionTraceLevel) {
00517             sprintState();
00518         }
00519 
00520         size_t i;
00521         for (i = 0; i < numberOfCycles; ++i) {
00522             if (!executeOneCycle()) {
00523                 return i;
00524             } else {
00525                 if (mExecutionTraceLevel) {
00526                     sprintState();
00527                 }
00528             }
00529         }
00530 
00531         return i;
00532     }
00533 
00534     // create opcodeTableByNumber and mOpcodeTableByCharacter from opcodeTable
00535     // create allOpcodeChars = a set of all defined short mnemonics
00536     //
00537     template <typename T>
00538     void machine<T>::initOpcodeTables(void)
00539     {
00540         // First, initialize opcodeTableByCharacter so that the num field
00541         // equals the char code, then replace the ones that are real opcodes:
00542 
00543         for (size_t i = 0; i < sizeof(mOpcodeTableByCharacter) / sizeof(mOpcodeTableByCharacter[0]); ++i) {
00544             mOpcodeTableByCharacter[i].longMnemonic = nullptr;
00545             mOpcodeTableByCharacter[i].shortMnemonic = (char)i;
00546             mOpcodeTableByCharacter[i].num = (decltype(mOpcodeTableByCharacter[i].num))(char)i;
00547         }
00548 
00549         for (auto details : mOpcodeTable) {
00550             mOpcodeTableByNumber[details.num] = details;
00551             mOpcodeTableByCharacter[(unsigned)details.shortMnemonic] = details;
00552             allOpcodeChars += details.shortMnemonic;
00553         }
00554     }
00555 
00556     template <typename T>
00557     const typename machine<T>::opcodeDetails& machine<T>::findByNumber(size_t n) const
00558     {
00559         if (n < NUMBER_OF_OPCODES) {
00560             return mOpcodeTableByNumber[n];
00561         } else {
00562             return mOpcodeTableByNumber[OP_NOP];
00563         }
00564     }
00565 
00566     // If c is a valid opcode, returns the details for it, where the num field is the opcode number,
00567     // If c is not an opcode, returns the details for it where the num field is the char value
00568     //
00569     template <typename T>
00570     const typename machine<T>::opcodeDetails& machine<T>::findByShortMnemonic(char c) const
00571     {
00572         if ((unsigned)c >= 256) {
00573             // out of range of a char, return as if NOP
00574             return mOpcodeTableByNumber[OP_NOP];
00575         }
00576 
00577         return mOpcodeTableByCharacter[(unsigned)c];
00578     }
00579 
00584     template <typename T>
00585     bool machine<T>::executeOneCycle(void)
00586     {
00587         size_t temp;
00588         size_t Op0;
00589         size_t Op1;  // temporaries
00590 
00591         // Because the enumerator values are in a well ordered range in the
00592         // switch statement below, a reasonable compiler is able to generate
00593         // a jump table, reducing the switch statement overhead to a minimum.
00594 
00595         switch(mem[pc]) {
00596             default:
00597             case OP_NOP:
00598                 incpc();
00599                 break;
00600 
00601             case OP_RESET:
00602                 pc = sp = 0;
00603                 nz = false;
00604                 break;
00605 
00606             case OP_HALT:
00607                 return false;
00608                 break;
00609 
00610             case OP_IN:
00611                 if (mDataInIdx != mDataIn.size()) {
00612                     decsp();
00613                     setnz(mem[sp] = trunc((size_t)(T)mDataIn[mDataInIdx]));
00614                     // don't increment the index past the last element
00615                     mDataInIdx = std::min(mDataInIdx + 1, mDataIn.size() - 1);
00616                     incpc();
00617                 } else if (mDataInIdx == 0 && mDataIn.size() == 0) {
00618                     // input zeros in lieu of an input stream
00619                     decsp();
00620                     setnz(mem[sp] = 0);
00621                     incpc();
00622                 } else {
00623                     // HALT if reached end of input - should never happen
00624                     // because we prevent dataInIdx from exceeding the string length.
00625                     return false;
00626                 }
00627                 break;
00628 
00629             case OP_OUT:
00630                 if (mOutputStream.size() < maxOutputStreamSize) {
00631                     mOutputStream += (char)(mem[sp] & 0xff);
00632                 }
00633 
00634                 if (mExecutionTraceLevel >= 1) {
00635                     std::cerr << "Output =====>(T) "
00636                          << std::to_string((unsigned char)(mem[sp] & 0xff))
00637                          << " = \'" << (char)(mem[sp] & 0xff) << "\'" << std::endl;
00638                 }
00639 
00640                 setnz(mem[sp] & 0xff);
00641                 incsp();
00642                 incpc();
00643 
00644                 break;
00645 
00646             case OP_POP:
00647                 setnz(mem[sp]);
00648                 incsp();
00649                 incpc();
00650                 break;
00651 
00652             case OP_DUP:
00653                 temp = mem[sp];
00654                 decsp();
00655                 setnz(mem[sp] = temp);
00656                 incpc();
00657                 break;
00658 
00659             case OP_PUSHPC:
00660                 decsp();
00661                 mem[sp] = trunc(pc);
00662                 incpc();
00663                 break;
00664 
00665             case OP_POPPC:
00666                 pc = mem[sp] % mArchLength;
00667                 incsp();
00668                 break;
00669 
00670             case OP_POPSP:
00671                 sp = mem[sp] % mArchLength;
00672                 incpc();
00673                 break;
00674 
00675             case OP_SPTGT: {
00676                 // find the next TARGET
00677                 bool found = false;
00678                 if (pc < mArchLength - 1) {
00679                     for (auto i = pc + 1; !found && i < mArchLength; ++i) {
00680                         if (mem[i] == OP_TARGET) {
00681                             sp = i;
00682                             found = true;
00683                             break;
00684                         }
00685                     }
00686                 }
00687 
00688                 incpc();
00689                 break; }
00690 
00691             case OP_PUSHNZ:
00692                 decsp();
00693                 mem[sp] = nz;
00694                 incpc();
00695                 break;
00696 
00697             case OP_SWAP:
00698                 temp = mem[sp];
00699                 mem[sp] = mem[(sp + 1) % mArchLength];
00700                 mem[(sp + 1) % mArchLength] = temp;
00701                 incpc();
00702                 break;
00703 
00704             case OP_PUSH0:
00705                 decsp();
00706                 mem[sp] = 0;
00707                 nz = 0;
00708                 incpc();
00709                 break;
00710 
00711             case OP_ADD:
00712                 decsp();
00713                 setnz(mem[sp] = trunc(mem[(sp + 2) % mArchLength] + mem[(sp + 1) % mArchLength]));
00714                 incpc();
00715                 break;
00716 
00717             case OP_SUB:
00718                 decsp();
00719                 setnz(mem[sp] = trunc(mem[(sp + 2) % mArchLength] - mem[(sp + 1) % mArchLength]));
00720                 incpc();
00721                 break;
00722 
00723             case OP_INC:
00724                 mem[sp] = trunc(mem[sp] + 1);
00725                 setnz(mem[sp]);
00726                 incpc();
00727                 break;
00728 
00729             case OP_DEC:
00730                 mem[sp] = trunc(mem[sp] - 1);
00731                 setnz(mem[sp]);
00732                 incpc();
00733                 break;
00734 
00735             case OP_MUL:
00736                 decsp();
00737                 setnz(mem[sp] = trunc(mem[(sp + 2) % mArchLength] * mem[(sp + 1) % mArchLength]));
00738                 incpc();
00739                 break;
00740 
00741             case OP_DIV: {
00742                 Op0 = mem[(sp + 1) % mArchLength];
00743                 Op1 = mem[sp];
00744                 if (Op1 == 0) {
00745                     // in this case, fudge the operands to produce the largest result:
00746                     Op0 = ~0;
00747                     Op1 = 1;
00748                 }
00749                 setnz(mem[(sp + 1) % mArchLength] = trunc(Op0 / Op1));
00750                 mem[sp] = trunc(Op0 % Op1);
00751                 incpc();
00752                 break; }
00753 
00754             case OP_XOR:
00755                 decsp();
00756                 setnz(mem[sp] = trunc(mem[(sp + 2) % mArchLength] ^ mem[(sp + 1) % mArchLength]));
00757                 incpc();
00758                 break;
00759 
00760             case OP_AND:
00761                 decsp();
00762                 setnz(mem[sp] = trunc(mem[(sp + 2) % mArchLength] & mem[(sp + 1) % mArchLength]));
00763                 incpc();
00764                 break;
00765 
00766             case OP_OR:
00767                 decsp();
00768                 setnz(mem[sp] = trunc(mem[(sp + 2) % mArchLength] | mem[(sp + 1) % mArchLength]));
00769                 incpc();
00770                 break;
00771 
00772             case OP_SHL:
00773                 setnz(mem[sp] = trunc(mem[sp] << 1));
00774                 incpc();
00775                 break;
00776 
00777             case OP_SHR:
00778                 setnz(mem[sp] = trunc(mem[sp] >> 1));
00779                 incpc();
00780                 break;
00781 
00782             case OP_NOT:
00783                 setnz(mem[sp] = trunc(~mem[sp]));
00784                 incpc();
00785                 break;
00786 
00787             case OP_BZ:
00788                 incpc();
00789                 if (!nz) {
00790                     incpc();
00791                 }
00792                 break;
00793 
00794             case OP_BNZ:
00795                 incpc();
00796                 if (nz) {
00797                     incpc();
00798                 }
00799                 break;
00800 
00801             case OP_BEQ:
00802                 incpc();
00803                 if (mem[(sp + 1) % mArchLength] == mem[sp]) {
00804                     incpc();
00805                 }
00806                 break;
00807 
00808             case OP_BGT:
00809                 incpc();
00810                 if (mem[(sp + 1) % mArchLength] > mem[sp]) {
00811                     incpc();
00812                 }
00813                 break;
00814 
00815             case OP_BLT:
00816                 incpc();
00817                 if (mem[(sp + 1) % mArchLength] < mem[sp]) {
00818                     incpc();
00819                 }
00820                 break;
00821 
00822             case OP_BGE:
00823                 incpc();
00824                 if (mem[(sp + 1) % mArchLength] >= mem[sp]) {
00825                     incpc();
00826                 }
00827                 break;
00828 
00829             case OP_LOOP:
00830                 // logic is in the std::endl opcode
00831                 incpc();
00832                 break;
00833 
00834             case OP_ENDL: {
00835                 // find the preceding LOOP
00836                 bool found = false;
00837                 if (pc > 0) {
00838                     for (size_t i = pc; !found && i > 0; ) {
00839                         --i;
00840                         if (mem[i] == OP_LOOP) {
00841                             pc = (i + 1) % mArchLength;
00842                             found = true;
00843                             break;
00844                         }
00845                     }
00846                 }
00847                 if (!found) {
00848                     incpc();
00849                 }
00850                 break; }
00851 
00852             case OP_BRAN: {
00853                 // find the next TARGET
00854                 bool found = false;
00855                 if (pc < mArchLength - 1) {
00856                     for (auto i = pc + 1; !found && i < mArchLength; ++i) {
00857                         if (mem[i] == OP_TARGET) {
00858                             pc = (i + 1) % mArchLength;
00859                             found = true;
00860                             break;
00861                         }
00862                     }
00863                 }
00864                 if (!found) {
00865                     incpc();
00866                 }
00867                 break; }
00868 
00869             case OP_BRAP: {
00870                 // find the preceding TARGET
00871                 bool found = false;
00872                 if (pc > 0) {
00873                     for (size_t i = pc; !found && i > 0; ) {
00874                         --i;
00875                         if (mem[i] == OP_TARGET) {
00876                             pc = (i + 1) % mArchLength;
00877                             found = true;
00878                             break;
00879                         }
00880                     }
00881                 }
00882                 if (!found) {
00883                     incpc();
00884                 }
00885                 break; }
00886 
00887             case OP_TARGET:
00888                 // logic is in the SPTGT, BRAN, and BRAP opcodes
00889                 incpc();
00890                 break;
00891 
00892             case OP_SKIP1: pc = (pc + 2) % mArchLength; break;
00893             case OP_SKIP2: pc = (pc + 3) % mArchLength; break;
00894             case OP_SKIP3: pc = (pc + 4) % mArchLength; break;
00895             case OP_SKIP4: pc = (pc + 5) % mArchLength; break;
00896             case OP_SKIP5: pc = (pc + 6) % mArchLength; break;
00897             case OP_SKIP6: pc = (pc + 7) % mArchLength; break;
00898             case OP_SKIP7: pc = (pc + 8) % mArchLength; break;
00899             case OP_SKIP8: pc = (pc + 9) % mArchLength; break;
00900             case OP_SKIP9: pc = (pc + 10) % mArchLength; break;
00901         };
00902 
00903         ++mCycleNumber;
00904 
00905         return true;
00906     }
00907 } // end namespace iota
00908 
00909 #endif  /* LITTLECOMPILER_H */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations