今回はEFlagsの更新をメソッドを定義する。その前に前回のソースコードの修正がある。set_carryメソッドだが、これはset_carry!メソッドの間違いである。!を付け忘れた…まだRubyに慣れてないからだろう。それで本題に入る。EFlagsの更新だが、これは四則演算やビット演算などの演算後に更新される。全てのフラグが更新されるわけではなく、演算によって更新されるフラグとそうでないフラグがある。Intelのマニュアルに載っているが、マニュアルの紹介は次回にするということで、今回はとりあえずフラグの更新部分と前に実装した足し算をフラグを更新するように変更をする。ただし、今回のフラグの更新については自信がない。あってるかどうかは不明である。というか間違っていると思う。とりあえずソースコードを載せる。追加したのは./vm/util/FlagCheck.rbのみ
FlagCheck.rb
module FlagCheck def add_check(target, value, result, eflags, bits) overflow = result & (1 << (bits - 1)) > 0 eflags.set_overflow!(overflow) check(target, result, eflags, bits) end def sub_check(target, value, result, eflags, bits) overflow = result & (1 << (bits - 1)) > 0 eflags.set_overflow!(overflow) check(target, result, eflags, bits) carry = (target < 0 && result > 0) || (target >= 0 && result < 0); eflags.set_carry!(carry); end def check(before, result, eflags, bits) flag = (result & (1 << bits)) > 0; eflags.set_carry!(flag); eflags.set_zero!(result == 0); flag = result < 0; eflags.set_sign!(flag); flag = ((before & 0x0F) == 0x0F && (result & 0x0F) != 0x0F) || ((before & 0x0F) != 0x0F && (result & 0x0F) == 0x0F); eflags.set_adjust!(flag); count = result & 0x01; count += (result >> 0x01) & 0x01; count += (result >> 0x02) & 0x01; count += (result >> 0x03) & 0x01; count += (result >> 0x04) & 0x01; count += (result >> 0x05) & 0x01; count += (result >> 0x06) & 0x01; count += (result >> 0x07) & 0x01; flag = (count % 2) == 0; eflags.set_parity!(flag); end module_function :add_check module_function :sub_check module_function :check end
これのadd_cehckをAddALImm8から呼び出す
require "./vm/util/FlagCheck.rb" require "./vm/register/RegisterIndex.rb" include RegisterIndex class AddALImm8 def execute(vm) al = vm.get_register8(EAX) value = vm.get_code8(1) result = al + value FlagCheck.add_check(al, value, result, vm.eflags, 8) vm.set_register8!(EAX, result) vm.add_eip!(2) end end
これで足し算後にフラグが更新される。次々回あたりにこれを利用したプログラムを用意する予定