スポンサーサイト
新しい記事を書く事で広告が消せます。
情報処理技術全般を気まぐれにつつくゆるいブログです。技術解説記事のソースは専門書と実務経験です。
using System;
namespace MiniBitMachine.V3
{
//命令の値(オペランド)が持つべきインタフェースの定義。
public interface IOperand
{
ushort Value { get; set; }
}
}
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
namespace MiniBitMachine.V3
{
//比較移動命令。
public class CompareMove :
Instruction,
IEquatable
{
//関係のないメンバーは省略
//命令長。
public static int Length { get { return 16; } }
//比較フラグ
private bool _compareFlag;
public bool CompareFlag
{
get { return this._compareFlag; }
set { this._compareFlag = value; }
}
//宛先。
private IEnumerable _destinationBinary;
private IOperand _destination;
public IOperand Destination
{
get { return this._destination; }
internal set { this._destination = value; }
}
//送信元。
private IEnumerable _sourceBinary;
private IOperand _source;
public IOperand Source
{
get { return this._source; }
internal set { this._source = value; }
}
//インスタンスを生成する。
public CompareMove() : this( null, null, "" )
{
}
//宛先と送信元を指定してインスタンスを生成する。
public CompareMove( IOperand destination, IOperand source )
: this( destination, source, "" )
{
}
//宛先と送信元とコメントを指定してインスタンスを生成する。
public CompareMove(
byte destination,
byte source,
string comment )
{
this._destinationBinary =
BitMaster.ConvertBinary( destination );
this._destination = new Immediate( destination );
this._sourceBinary =
BitMaster.ConvertBinary( source );
this._source = new Immediate( source );
this.Comment = comment;
}
//宛先と送信元とコメントを指定してインスタンスを生成する。
public CompareMove(
IOperand destination,
IOperand source,
string comment )
{
if ( destination != null )
this._destinationBinary =
BitMaster.ConvertBinary( ( byte ) destination.Value );
this._destination = destination;
if ( source != null )
this._sourceBinary =
BitMaster.ConvertBinary( ( byte ) source.Value );
this._source = source;
this.Comment = comment;
}
//バイナリ値からインスタンスを生成する。
public CompareMove( IEnumerable binary )
{
if ( binary.Count( ) != CompareMove.Length )
throw new ArgumentException(
String.Format(
"必ず{0}ビットの値を指定してください。",
CompareMove.Length ) );
this._destinationBinary =
binary.Where(
( b, index ) =>
( index < 8 ) ).Select( b => b );
this._destination = new Immediate(
BitMaster.ConvertToByte( this._destinationBinary ) );
this._sourceBinary =
binary.Where(
( b, index ) =>
( index >= 8 ) ).Select( b => b );
this._source = new Immediate(
BitMaster.ConvertToByte( this._sourceBinary ) );
}
//命令を実行する。
public virtual void Execute()
{
if ( this._compareFlag )
this.Destination.Value = this.Source.Value;
}
}
}
これで値を持つオブジェクトに対して、比較移動を使用できるようになりました。比較移動命令を変更すると、実行部分を変更する必要が生じるのでます。その方法として、実行を担当するExecuterオブジェクトを変更する手もありますが、それでは実行と解析の役割を兼用することになってしまいます。何故ならば、インタフェースを実装するオブジェクトを設定するコードドが必要になるからです。
using System;
using System.Collections.Generic;
namespace MiniBitMachine.V3
{
//命令を解析するオブジェクト。
public class Decoder
{
//実行に必要な情報。
ExecuteEnvironment _exeInfo;
//アドレスを管理するオブジェクト。
Addresser _addresser;
//解析に必要な情報を指定し、
//インスタンスを生成する。
public Decoder(
ExecuteEnvironment exeInfo,
Addresser addresser )
{
this._addresser = addresser;
this._exeInfo = exeInfo;
}
//命令をデコードする。
public CompareMove Decode( IEnumerable<bool> binary )
{
CompareMove temp = new CompareMove( binary );
CompareMove result = this.SetOperand( temp );
return result;
}
//オペランドを設定する。
private CompareMove SetOperand( CompareMove command )
{
if ( command.Destination.Value ==
this._exeInfo.CompareFlagAddress ) {
return SetCompareFlagOperand( command );
} else if ( command.Destination.Value ==
this._exeInfo.ProgramCounterAddress ) {
return SetProgramCounterOperand( command );
} else if ( command.Destination.Value ==
this._exeInfo.LastAddress ) {
return SetStopCpuOperand( command );
} else {
return SetMemoryOperand( command );
}
}
//比較フラグに関するオペランドを用意する。
private CompareMove SetCompareFlagOperand( CompareMove command )
{
command.CompareFlag = true;
command.Destination = this._exeInfo.CompareFlag;
command.Source = this.GetSource( command );
return command;
}
//プログラムカウンタに関するオペランドを用意する。
private CompareMove SetProgramCounterOperand( CompareMove command )
{
command.CompareFlag = this._exeInfo.GetCompareFlag();
command.Destination = this._addresser.ProgramCounter;
return command;
}
//CPU停止に関するオペランドを用意する。
private CompareMove SetStopCpuOperand( CompareMove command )
{
command.CompareFlag = false;
this._exeInfo.IsStop.Value = 1;
command.Source = this.GetSource( command );
return command;
}
//メモリに関するオペランドを用意する。
private CompareMove SetMemoryOperand( CompareMove command )
{
MemorySnapShot destination =
new MemorySnapShot(
this._addresser,
this._exeInfo.ReferenceMemory,
command.Destination.Value );
command.CompareFlag = this._exeInfo.GetCompareFlag( );
command.Destination = destination;
command.Source = new Immediate( command.Source.Value );
return command;
}
//メモリ用のソースを取得する。
private IOperand GetSource( CompareMove command )
{
IOperand result = new MemorySnapShot(
this._addresser,
this._exeInfo.ReferenceMemory,
command.Source.Value );
return result;
}
}
}
さらにやるべきことがあります。それは、レジスタオブジェクトと、メモリの一時状態(スナップショット)が必要です。なぜならば、IOperandインタフェースを実装しないと、比較移動命令に指定できないからです。