マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

フラグの更新 #11

今回は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

これで足し算後にフラグが更新される。次々回あたりにこれを利用したプログラムを用意する予定