ダウンロード 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ビット)
- EBX(ダブルワード:32ビット)
- ECX(ダブルワード:32ビット)
- EDX(ダブルワード:32ビット)

レジスタのビット数に注意しながら、各レジスタを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構造体がなければ、すべてのプロパティにビットごとの論理積を求めなくてはなりません。こんな状態では誰でもミスをおかします。プログラミングはミスがつきものですから、なるべくミスがおきにくい状態に持っていくことが肝要です。
なお、全プロパティの型は符号なしに設定します。理由は、数値の符号の有無は機械語で決まるからです。もし、符号ありの型にしてしまうと、符号を考慮しない機械語の命令の実装が難しくなってしまいます。
この記事は参考になりましたか?
- この記事の著者
-
インドリ(インドリ)
分析・設計・実装なんでもありのフリーエンジニア。ブログ「無差別に技術をついばむ鳥(http://indori.blog32.fc2.com/)」の作者です。アドバイザーをしたり、システム開発したり、情報処理技術を研究したりと色々しています。座右の銘は温故知新で、新旧関係なく必要だと考えたものは全て学...
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
