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

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

某イベント用の簡易x86エミュレータ(1)

某イベントで作る簡易x86エミュレータを公開しておく。この時点だと、まだフラグも無いし汎用レジスタも4つしか用意してないし、セグメントレジスタが無い。しかもプログラムカウンタは0から始めておくというもの。できるだけわかりやすく説明したいです…はい。読み込むプログラムは某イベント用にアセンブリ言語でプログラムを書くアセンブルしたもの

import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;

public class Emulator{
    private byte[] memory;   //プログラムを格納するメモリ
    private int[] registers; //レジスタ郡
    private int eip;         //プログラムカウンタ

    public static final int DEFAULT_MEMORY_SIZE = 1 * 1024 * 1024;
    public static final int AL = 0;
    public static final int CL = 1;
    public static final int DL = 2;
    public static final int BL = 3;
    
    public Emulator(int memorySize){
        memory = new byte[memorySize]; //プログラムを格納する領域の確保
        registers = new int[4];        //現在はレジスタ4つしか使わない
        eip = 0;                       //プログラムカウンタ
    }
    
    public void read(String fileName) throws IOException{
        BufferedInputStream input = null;

        try{
            input = new BufferedInputStream(new FileInputStream(fileName));

            //プログラムを読み込む
            input.read(memory);
            input.close();
        }catch(IOException e){
            if(input != null){
                try{
                    input.close();
                }catch(IOException ioe){
                    throw ioe;
                }
            }
            
            throw e;
        }
    }
    
    public void execute(){
        //オペコードの取得
        int code = memory[eip] & 0xFF;
        
        //オペコードを表示する
        System.out.printf("code = %X\n", code);
        
        if(code == 0xB0){
            //代入を行う
            int value = memory[eip + 1] & 0xFF;
            System.out.printf("MOV AL, 0x%X\n", value);
            
            registers[Emulator.AL] = value;
            eip += 2;
        }else if(code == 0x04){
            //足し算を行う
            int value = memory[eip + 1] & 0xFF;
            System.out.printf("ADD AL, 0x%X\n", value);
            
            registers[Emulator.AL] += value;
            eip += 2;
        }else if(code == 0xEB){
            //ジャンプ命令を実行する
            int value = memory[eip + 1];
            System.out.printf("JMP 0x%X\n", value & 0xFF);
            
            eip += value;
            eip += 2;
        }
    }

    public void dumpRegisters(){
        //レジスタを全て出力する
        System.out.println();
        System.out.println("Registers Value");
        System.out.printf("AL = %X\n", registers[Emulator.AL]);
        System.out.printf("CL = %X\n", registers[Emulator.CL]);
        System.out.printf("DL = %X\n", registers[Emulator.DL]);
        System.out.printf("BL = %X\n", registers[Emulator.BL]);
        
        System.out.printf("EIP = %X\n", eip);
    }
    
    public static void main(String[] args){
        if(args.length == 0){
            System.out.println("引数で読み込むファイルを指定してください");
            System.exit(0);
        }

        try{
            Emulator emulator = new Emulator(Emulator.DEFAULT_MEMORY_SIZE);    

            emulator.read(args[0]);
            emulator.execute();
            emulator.execute();
            emulator.execute();

            emulator.dumpRegisters();
        }catch(IOException e){
            System.out.println("ファイルの読み込みに失敗しました。");
            e.printStackTrace();
       }
    }
}