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

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

条件分岐 その2 #14

今回はCMP命令とJB命令を使って条件分岐を行う。CMP命令は2つのオペランドを使い引き算を行って、フラグレジスタを更新する。ソースオペランドがデスティネーションオペランドより小さいとか大きいとか、同じ値だとかの情報をフラグレジスタに設定する。引き算の結果はレジスタには保存されない。またJB命令はフラグレジスタのCarryフラグを見てジャンプするかどうかを決める。前に行った引き算でソースオペランドがデスティネーションオペランドより小さい場合(1-2や3-5など)などを行った場合に設定される。そして今回実行するプログラムは
comp_jb 直
で、中身は

    MOV AL, 0x04
    CMP AL, 0x05
    
    JB move16

fin:
    JMP fin

move16:
    MOV AL, 0x10
    JMP fin

をnasmでアセンブルしたものである。内容はほぼ前回の足し算と同じで、ADDやJEの代わりに今回はCMP命令とJBを使って分岐を行っている。これを実行するために作ったファイルは

./vm/instruction/cmp/CMPALImm8.rb
./vm/instruction/jump/JB.rb

で、ソースコード

CMPALImm8.rb

require "./vm/util/FlagCheck.rb"
require "./vm/register/RegisterIndex.rb"
include RegisterIndex

class CMPALImm8
    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.add_eip!(2)
    end
end

JB.rb

class JB
    def execute(vm)
        if(vm.eflags().carry?()) then
            vm.add_eip!(vm.get_signed_code8(1))
        end
        
        vm.add_eip!(2)
    end
end

となっている。これを実行するために、InstructionMapを変更する。

@instructions[0x3C] = CMPALImm8.new()
@instructions[0x72] = JB.new()

requireも忘れずに

require "./vm/instruction/cmp/CMPALImm8.rb"
require "./vm/instruction/jump/JB.rb"

これでcomp_jbを読み込んで実行できるようになる。comp_jbを読み込むと、ALに4が代入され、その後CMPでALと5の比較が行われる。今回はソースオペランドのALの方が小さいため、Carryフラグが立ちJB命令でmove16にたどり着く。あとは前回のADDと同じである。次回はHello World!のプログラムを読み込ませるとしよう。説明が大変そうだけど頑張る