ADD命令の実装
実装する前に、まずはADD命令について説明します。ADD命令は加算(足し算)を行う命令です。しかし、人間とは違いCPUは些細な事が問題となります。ADD命令では限界値をオーバーした場合どうするのかが問題となります。文章だけでは分かりにくいので例を挙げて説明します。
例えば、ALレジスタ(1バイト)にADD命令を適用するにあたり、下記のような場合はどうなるでしょうか?
- MOV命令を使って0で初期化する。AL=0.
- ADD al, 200: ALに200を足します。AL=200.
- ADD al, 200: ALに再び200を足します。ALは255までしか扱えないので問題発生!
この例の様な状況の時Intel社のCPUは、CF(キャリーフラグ)というフラグを1にして桁あふれ(オーバーフロー)した事を外部に知らせます。そして、余分なビットを無視します。
ですから、上記例3の場合は
200(2進表記で1100 1000)+
200(2進表記で1100 1000)
=400(2新表記で1 1001 0000)
で答えが9ビットになってしまうので、余分な先頭1ビット無視して、答えを144(2新表記で1001 0000)にし、CF=1にします。
これを表現するためには、IntelCpuオブジェクトに新しいプロパティとフィールドが必要になります。次のプロパティとフィールドを追加してください。
'オーバーフローを知らせるフラグ Private m_cf As Boolean = False Public Property CF() As Boolean Get Return Me.m_cf End Get Private Set(ByVal value As Boolean) Me.m_cf = value End Set End Property
桁あふれに注意しながらADD命令を実装すると、次のとおりになります。
'ADD命令の実装 Private Sub Add(ByVal ope As OpeCode) Select Case ope.Destination Case RegisterName.AL Dim tmp As UShort = Me.AL + CUShort(ope.Value.ValueLowByte) If Byte.MaxValue >= tmp Then Me.AL = tmp Else '桁あふれ(オーバーフロー)が発生 Me.CF = True '上位ビットを消す tmp = tmp And &HFF '計算結果を設定 Me.AL = CByte(tmp) End If Case RegisterName.EAX Dim tmp As ULong = Me.EAX + CULng(ope.Value.ValueU32) If UInteger.MaxValue >= tmp Then Me.CF = False Me.EAX = tmp Else '桁あふれ(オーバーフロー)が発生 Me.CF = True '上位ビットを消す tmp = tmp And UInteger.MaxValue '計算結果を設定 Me.EAX = CUInt(tmp) End If End Select End Sub
では実装内容を説明します。まず、対象レジスタの現在値と指定された値を加算します。この時注意しなくてはならないのは「直接レジスタプロパティに加算してはならない」ことと、「オーバーフロー対策のために、レジスタプロパティよりも大きな値が格納できる型を使用する」ことです。これは、オーバーフローが発生する可能性があるからです。もしオーバーフローが発生してしまうと、例外がスローされてしまいます。そうならないためには一時的に、大きな値を格納できる型が必要となります。
次に必要なのは、オーバーフローのチェックとオーバーフロー時の対応です。先ほど説明したように、ADD命令ではオーバーフローが発生した際には余分なビットを切り捨てて、CFフラグを1(True)にしなくてはなりません。そのためには、ビットごとのAnd論理和を使用します。
この大まかな流れが分かれば、ADD命令の実装を理解出来ます。しかし、ひとつだけVB.NETの性質が影響する注意点があります。それはこのプログラムです。
tmp = tmp And UInteger.MaxValue
今まで筆者は&HFFFFというふうに16進数で指定していましたが、今回はそれができません。何故かというと、VB.NETでは「&H」はInteger型だと見なされているからです。それゆえ、今回のUInteger型のビットは得られませんので、仕方がなくUInteger.MaxValue
プロパティを使用する事にしました。バイナリプロプログラミングでは、常に桁数が重要となってくるのです。
これでIntelCpuオブジェクトのADD命令の実装が終わりましたので、次はテストドライバ側の変更を行います。