iota-machine
|
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 */