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()); } }


