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

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

MOV AL, 1を実行 #4

MOV AL, 1を実行できるようにしてみた。追加したファイルは以下の通り。またemulator.rbとVM.rbを変更している。

./vm/instruction/InstructionMap.rb
./vm/instruction/move/MoveRImm8.rb

読み込んでいるファイルはadd 直

まずはMoveRImm8.rbから

class MoveRImm8
    def initialize(index)
        @index = index
    end
    
    def execute(vm)
        vm.setRegister8(@index, vm.getCode(1))
        vm.addEIP(2);
    end
end

このクラスは命令コード0xB0〜0xB7までを扱うものである。命令コード0xB0 + indexのときにexecuteが呼ばレジスタ番号index番目の8bitレジスタに値を代入する。代入が終わったらプログラムカウンタ(EIP)を命令長の分だけ増加させている

次にInstructionMap.rb

require "./vm/instruction/move/MoveRImm8.rb"

class InstructionMap
    def initialize()
        @instructions = Array.new(256)
        
        for i in 0..7
            @instructions[0xB0 + i] = MoveRImm8.new(i)
        end
    end
    
    def getInstruction(code)
        return @instructions[code]
    end
end

このクラスは命令コードとそれに対応するオブジェクトを関連付けるもの。現在は0xB0〜0xB7までをMoveRImm8のオブジェクトに対応させている。

次にVM.rb

require "./vm/instruction/InstructionMap.rb"
require "./vm/register/RegisterIndex.rb"

include RegisterIndex

class VM
    def initialize(memorySize)
        @registers = Array.new(RegisterCount);
        @memory = Array.new(memorySize);
        @instructions = InstructionMap.new()
        
        for i in 0..RegisterCount - 1
            @registers[i] = 0
        end
    end
    
    def load(fileName)
        file = open(fileName)
        file.binmode()
        
        buf = file.read(512)
        count = buf.size < 512 ? buf.size - 1 : 511
        
        for i in 0..count
            @memory[0x7C00 + i] = buf[i]
        end
        
        file.close()
        @registers[EIP] = 0x7C00
    end
    
    def execute()
        code = getCode()
        instruction = @instructions.getInstruction(code)
        instruction.execute(self)
        
        #命令コードと実行したクラスを表示
        puts code.to_s(16) + ": " + instruction.class().to_s()
        
        #EAXの値を表示する
        puts "EAX = " + @registers[EAX].to_s(16)
        
        #EIPの値を表示する
        puts "EIP = " + @registers[EIP].to_s(16)
    end
    
    def getCode(index = 0)
        return @memory[@registers[EIP] + index].unpack("C")[0]
    end
    
    #8bitレジスタに値を設定する。indexが4未満かどうかで呼び出すメソッド分岐
    def setRegister8(index, data)
        if index < 4 then
            setRegister8Low(index, data)
        else
            setRegister8High(index - 4, data)
        end
    end

    #下位8bitレジスタに値を設定する
    def setRegister8Low(index, data)
        @registers[index] &= 0xFFFFFF00;
        @registers[index] |= (data & 0xFF);
    end
    
    #上位8bitレジスタに値を設定する
    def setRegister8High(index, data)
        @registers[index] &= 0xFFFF00FF;
        @registers[index] |= (data & 0xFF) << 8;
    end

    def addEIP(value)
        @registers[EIP] += value
    end
end

変更点は追加したexecute、setRegister8やaddEIPなど。これからもどんどん変更していく

最後にemulator.rb

#! ruby -Ks

require "./vm/VM.rb"

if ARGV.size == 0 then
    puts "ファイル名を指定してください"
    exit()
end

vm = VM.new(1 * 1024 * 1024)
vm.load(ARGV[0])
vm.execute()

vm#executeを呼び出すようにしている。次回は実行できる命令を増やすか