CodeZine(コードジン)

特集ページ一覧

VB.NETで仮想CPUを作ろう (3) - 仮想CPUのGUI化

VB.NETで学ぶ機械語の基礎 第3回

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/07/29 14:00

ダウンロード VirtualCPU3.zip (193.3 KB)

本稿では、VB.NETを利用し、簡単な機械語で動く仮想CPUを作ることでバイナリプログラミングを満喫します。実際の業務で直接使えるケースは少ないと思いますが、デバッグやプログラミングの地力向上に役立つでしょう。今回はCPUの基本動作を実装するとともに、それをGUIで確認できるようにします。

目次

はじめに

 本記事はVB.NETの初歩的な記法だけを使って、簡単な機械語で動く仮想CPUの実装法を解説します(※CPUにもいろいろありますが、この記事ではIntel社が製造しているCPUを対象とします)。その過程を通じて、初心者でもバイナリプログラミングが楽しめることと、バイナリプログラミングの魅力を伝えたいと思っています。前回は、仮想CPUの必須項目であるレジスタを実装しました。今回は、さらに仮想CPUの実装を進めます。

下準備

 今回は前回の実装を拡張していきますので、あらかじめ前回までの部分の実装を済ませておいてください。後は専門用語とCPU構造の確認のため、第1回で用意した3つのIntel社のマニュアルをすぐ読める状態にしてください。

仮想CPUにレジスタを実装

 前回は仮想CPU実装を簡単にするためにレジスタ構造体を実装しました。これで、いよいよ仮想CPUクラスを作成する準備が整ったことになります。では、早速CPUをエミュレートするクラスを作りましょう。名前はIntel製であることを考慮してIntelCpuにします。IntelCpu.vbファイルを前回作ったプロジェクトに追加してください。

Public Class IntelCpu

End Class

 これでCPUクラスの大まかな定義ができました。まずは実装するレジスタを確認してから、このIntelCpuクラスにレジスタプロパティを実装します。実装するレジスタは次のとおりです。

  • EAX(ダブルワード:32ビット)
  • AX(1ワード:16ビット)、AH(1バイト:8ビット)、AL(1バイト:8ビット)を内包しています。
     
  • EBX(ダブルワード:32ビット)
  • BX(1ワード:16ビット)、BH(1バイト:8ビット)、BL(1バイト:8ビット)を内包しています。
     
  • ECX(ダブルワード:32ビット)
  • CX(1ワード:16ビット)、CH(1バイト:8ビット)、CL(1バイト:8ビット)を内包しています。
     
  • EDX(ダブルワード:32ビット)
  • DX(1ワード:16ビット)、DH(1バイト:8ビット)、DL(1バイト:8ビット)を内包しています。
イメージ
イメージ

 レジスタのビット数に注意しながら、各レジスタをIntelCpuのプロパティとして実装すると次のようになります。

Public Class IntelCpu

#Region "EAXレジスタ"
    Private m_eax As Register
    Private Property EAX() As UInteger
        Get
            Return Me.m_eax.ValueU32
        End Get
        Set(ByVal value As UInteger)
            Me.m_eax.ValueU32 = value
        End Set
    End Property

    Private Property AX() As UShort
        Get
            Return Me.m_eax.ValueU16
        End Get
        Set(ByVal value As UShort)
            Me.m_eax.ValueU16 = value
        End Set
    End Property

    Private Property AH() As Byte
        Get
            Return Me.m_eax.ValueHighByte
        End Get
        Set(ByVal value As Byte)
            Me.m_eax.ValueHighByte = value
        End Set
    End Property

    Private Property AL() As Byte
        Get
            Return Me.m_eax.ValueLowByte
        End Get
        Set(ByVal value As Byte)
            Me.m_eax.ValueLowByte = value
        End Set
    End Property

#End Region

#Region "EBXレジスタ"
    Private m_ebx As Register
    Private Property EBX() As UInteger
        Get
            Return Me.m_ebx.ValueU32
        End Get
        Set(ByVal value As UInteger)
            Me.m_ebx.ValueU32 = value
        End Set
    End Property

    Private Property BX() As UShort
        Get
            Return Me.m_ebx.ValueU16
        End Get
        Set(ByVal value As UShort)
            Me.m_ebx.ValueU16 = value
        End Set
    End Property

    Private Property BH() As Byte
        Get
            Return Me.m_ebx.ValueHighByte
        End Get
        Set(ByVal value As Byte)
            Me.m_ebx.ValueHighByte = value
        End Set
    End Property

    Private Property BL() As Byte
        Get
            Return Me.m_ebx.ValueLowByte
        End Get
        Set(ByVal value As Byte)
            Me.m_ebx.ValueLowByte = value
        End Set
    End Property

#End Region

#Region "ECXレジスタ"
    Private m_ecx As Register
    Private Property ECX() As UInteger
        Get
            Return Me.m_ecx.ValueU32
        End Get

        Set(ByVal value As UInteger)
            Me.m_ecx.ValueU32 = value
        End Set
    End Property

    Private Property CX() As UShort
        Get
            Return Me.m_ecx.ValueU16
        End Get
        Set(ByVal value As UShort)
            Me.m_ecx.ValueU16 = value
        End Set
    End Property

    Private Property CH() As Byte
        Get
            Return Me.m_ecx.ValueHighByte
        End Get
        Set(ByVal value As Byte)
            Me.m_ecx.ValueHighByte = value
        End Set
    End Property

    Private Property CL() As Byte
        Get
            Return Me.m_ecx.ValueLowByte
        End Get
        Set(ByVal value As Byte)
            Me.m_ecx.ValueLowByte = value
        End Set
    End Property

#End Region

#Region "EDXレジスタ"
    Private m_edx As Register
    Private Property EDX() As UInteger
        Get
            Return Me.m_edx.ValueU32
        End Get
        Set(ByVal value As UInteger)
            Me.m_edx.ValueU32 = value
        End Set
    End Property

    Private Property DX() As UShort
        Get
            Return Me.m_edx.ValueU16
        End Get
        Set(ByVal value As UShort)
            Me.m_edx.ValueU16 = value
        End Set
    End Property

    Private Property DH() As Byte
        Get
            Return Me.m_edx.ValueHighByte
        End Get
        Set(ByVal value As Byte)
            Me.m_edx.ValueHighByte = value
        End Set
    End Property

    Private Property DL() As Byte
        Get
            Return Me.m_edx.ValueLowByte
        End Get
        Set(ByVal value As Byte)
            Me.m_edx.ValueLowByte = value
        End Set
    End Property

#End Region

End Class

 この作業を通じてRegister構造体メリットが実感できると思います。Register構造体がなければ、すべてのプロパティにビットごとの論理積を求めなくてはなりません。こんな状態では誰でもミスをおかします。プログラミングはミスがつきものですから、なるべくミスがおきにくい状態に持っていくことが肝要です。

 なお、全プロパティの型は符号なしに設定します。理由は、数値の符号の有無は機械語で決まるからです。もし、符号ありの型にしてしまうと、符号を考慮しない機械語の命令の実装が難しくなってしまいます。


  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • インドリ(インドリ)

    分析・設計・実装なんでもありのフリーエンジニア。 ブログ「無差別に技術をついばむ鳥(http://indori.blog32.fc2.com/)」の作者です。 アドバイザーをしたり、システム開発したり、情報処理技術を研究したりと色々しています。 座右の銘は温故知新で、新旧関係なく必要だと考えた...

バックナンバー

連載:VB.NETで学ぶ機械語の基礎

もっと読む

All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5