非専門的シンギュラリティー研究所

無限に動き続けるシステムを表す方法を AI なども使って考えていきます。

アセンブラ(13)

executeInstruction 関数の処理(7) シフト系命令

シフト系命令には以下のようなものがあります。

lsl, lsr, asl, asr
  • 「lsl src, dst」、「asl src, dst」は dst を src ビット左シフトしたものを dst に設定します。「lsl dst」、「asl dst」は dst を 1 ビット左シフトしたものを dst に設定します。
  • 「lsr src, dst」、「asr src, dst」は dst を src ビット右シフトしたものを dst に設定します。「lsr dst」、「asr dst」は dst を 1 ビット右シフトしたものを dst に設定します。

空いたビットは asr では最上位ビット、それ以外では 0 となります。

フラグは N と Z は値によって変化し、V は asl、asr で符号が変わったとき 1、そうでないとき 0 です。C、X は最後に押し出されたビットです。

    else if (instruction.is_shift_instruction()) {
        // シフト命令の処理
        int32_t src_value;
        int dst_index = 1; // デフォルトは2番目のオペランド
        if (operands.size() == 1) {
            src_value = 1;
            dst_index = 0;
        }
        else if (operands.size() == 2) {
            src_value = operands[0].get_value(instruction.data_size());
            dst_index = 1;
        }
        else {
            cerr << "Invalid shift instruction: " << line << endl;
            return;
        }
        Operand& dst = operands[dst_index];
        int64_t dst_value = dst.get_value(instruction.data_size());
        bool extend = false; // 拡張フラグの初期化
        int64_t llresult;
        if (instruction.is_left_shift()) {
            llresult = dst_value << src_value;
            extend = llresult & (1LL << (instruction.data_size() * 8));
            dst.set_value(static_cast<uint32_t>(llresult), instruction.data_size());
        }
        else {
            if (src_value == 0) {
                llresult = dst_value; // シフト量が0の場合はそのまま
                extend = false; // 拡張フラグはセットしない
            }
            else if (instruction.is_logical_shift()) {
                llresult = static_cast<uint32_t>(dst_value) >> src_value; // 論理シフト
                extend = (dst_value & (1LL << (src_value - 1))) != 0; // 右に押し出されるビットのチェック
            }
            else {
                llresult = dst_value >> src_value; // 算術シフト
                extend = (dst_value & (1LL << (src_value - 1))) != 0; // 右に押し出されるビットのチェック
            }
            dst.set_value(static_cast<uint32_t>(llresult), instruction.data_size());
        }
        if (instruction.modifies_flags()) {
            cpu.set_shift_status(static_cast<uint32_t>(llresult), extend, instruction.data_size(), instruction.is_logical_shift());
        }
    }
rol, roxl, ror, roxr
  • 「rol dst」は dst を 1 ビット左シフトしたものを dst に設定します。空いたビットは dst の最上位ビットとなります。「rol src, dst」は「rol dst」を src 回繰り返します。
  • 「roxl dst」は dst を 1 ビット左シフトしたものを dst に設定します。空いたビットは X フラグの値となり、X フラグは dst の最上位ビットとなります。「roxl src, dst」は「roxl dst」を src 回繰り返します。
  • ror dst」は dst を 1 ビット右シフトしたものを dst に設定します。空いたビットは dst の最下位ビットとなります。「ror src, dst」は「ror dst」を src 回繰り返します。
  • 「roxr dst」は dst を 1 ビット左シフトしたものを dst に設定します。空いたビットは X フラグの値となり、X フラグは dst の最下位ビットとなります。「roxr src, dst」は「roxr dst」を src 回繰り返します。

フラグは N と Z は値によって変化し、V は 0、C、X は最後に押し出されたビットです。

    else if (instruction.is_rotate_instruction()) {
        // ローテート命令の処理
        int32_t src_value;
        int dst_index = 1; // デフォルトは2番目のオペランド
        if (operands.size() == 1) {
            src_value = 1;
            dst_index = 0;
        }
        else if (operands.size() == 2) {
            src_value = operands[0].get_value(instruction.data_size());
            dst_index = 1;
        }
        else {
            cerr << "Invalid rotate instruction: " << line << endl;
            return;
        }
        Operand& dst = operands[dst_index];
        int64_t dst_value = dst.get_value(instruction.data_size());
        bool extend = false; // 拡張フラグの初期化
        int64_t llresult;
        if (instruction.is_left_rotate()) {
            if (src_value == 0) {
                llresult = dst_value; // シフト量が0の場合はそのまま
                extend = false; // 拡張フラグはセットしない
            }
            else if (instruction.is_extended_rotate()) {
                int64_t extend_bit = (extend ? 1 : 0);
                llresult = dst_value | (extend_bit << (instruction.data_size() * 8));
                for (int i = 0; i < src_value; ++i) {
                    // 左ローテートの処理
                    llresult = (llresult << 1) | (llresult >> (instruction.data_size() * 8)) & 1;
                }
                extend = llresult & (1LL << (instruction.data_size() * 8));
            }
            else
            {
                llresult = dst_value;
                for (int i = 0; i < src_value; ++i) {
                    // 左ローテートの処理
                    llresult = (llresult << 1) | (llresult >> (instruction.data_size() * 8 - 1)) & 1;
				}
                extend = llresult & (1LL << (instruction.data_size() * 8));
            }
        }
        else {
            if (src_value == 0) {
                llresult = dst_value; // シフト量が0の場合はそのまま
                extend = false; // 拡張フラグはセットしない
            }
            else if (instruction.is_extended_rotate()) {
                int64_t extend_bit = (extend ? 1 : 0);
                llresult = dst_value | (extend_bit << (instruction.data_size() * 8));
                for (int i = 0; i < src_value; ++i) {
                    // 右ローテートの処理
                    llresult = (llresult >> 1) | ((llresult & 1) << (instruction.data_size() * 8));
                }
                extend = llresult & (1LL << (instruction.data_size() * 8 - 1));
            }
            else {
                llresult = dst_value;
                for (int i = 0; i < src_value; ++i) {
                    // 右ローテートの処理
                    llresult = (llresult >> 1) | ((llresult & 1) << (instruction.data_size() * 8 - 1));
				}
                extend = llresult & (1LL << (instruction.data_size() * 8));
            }
        }
        dst.set_value(static_cast<uint32_t>(llresult), instruction.data_size());
        if (instruction.modifies_flags()) {
            cpu.set_rotate_status(static_cast<uint32_t>(llresult), extend, instruction.data_size(), instruction.is_extended_rotate());
        }
    }