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を呼び出すようにしている。次回は実行できる命令を増やすか