
■ リピートプリフィックス・ストリング命令 ■
前回はアセンブラ言語を使用してデータをコピーするプログラ
ムを作成してみました。
前回のリストをもう1度見てみましょう。
─↓loop2.c──────────────────────
#include <stdio.h>
int main(void);
int sub(char*, char*);
int main()
{
int i;
char a[8]={ 0, 1, 2, 3, 4, 5, 6, 7};
char b[8]={10,11,12,13,14,15,16,17};
for(i=0;i<8;i++)
{
printf("a[%d]:%d b[%d]:%d\n", i, a[i], i, b[i]);
}
sub(&a[0], &b[0]);
for(i=0;i<8;i++)
{
printf("a[%d]:%d b[%d]:%d\n", i, a[i], i, b[i]);
}
return 0;
}
int sub(char* a, char* b)
{
printf("sub routine called\n");
_asm{
mov edi, a
mov esi, b
mov ecx, 8
LOOP1:
mov al, [esi] ;←データbをレジスタに移動
mov [edi], al ;←レジスタの中身をデータaに移動
add edi, 1 ;←データbのアドレスを1加算
add esi, 1 ;←データaのアドレスを1加算
loop LOOP1 ;←ecxの回数分ループ
}
}
─↑ここまで──────────────────────
今回はこれをもっと効率の良いコードに改造します。
前回作成した"loop2.c"というファイルをコピー&貼り付けし
て、新しく出来たファイルを"rep.c"という名前に変えておき
ましょう。
今回はこの"rep.c"に変更を加えていきます。
今回は非常に簡単です。
まず、メイン関数に変更はありません。そのまま使いましょう。
次にサブ関数ですが、こちらもほんの少し変更するだけです。
インラインアセンブラの部分を以下の様に変更してください。
─↓ここから──────────────────────
_asm{
mov edi, a ;前回と同じ
mov esi, b ;前回と同じ
mov ecx, 8 ;前回と同じ
rep movsb ;ここを変更
}
─↑ここまで──────────────────────
以上で終了です。
非常に簡単ですよね?
これだけのコードで前回作成したコピー処理と全く同じ事を行
ってくれます。
何故?という声が聞こえてきそうですので今から説明します。
まず、最初の3行の説明は良いですよね?
mov edi, a ;データaのアドレスをediに格納
mov esi, b ;データbのアドレスをesiに格納
mov ecx, 8 ;繰り返し回数をecxに格納
rep movsb
最初の3行までは前回と全く同じです。
次に、最後の1行
rep movsb
の説明をします。
「rep」というのは、直後の命令をecxレジスタの回数だけ繰り
返しなさい、という命令です。
そして直後の命令には「movsb」という命令があります。
これはメモリ上の「esi」レジスタ番目から1バイトのデータ
を持ってきて、メモリ上の「edi」レジスタ番目に格納しなさ
い、という命令です。
更にこの時、同時に「esi」レジスタと「edi」レジスタに1加
算する事も行なってくれます。
つまり、前回一生懸命作成したコピー処理の部分である、
LOOP1:
mov al, [esi] ;←データbをレジスタに移動
mov [edi], al ;←レジスタの中身をデータaに移動
add edi, 1 ;←データbのアドレスを1加算
add esi, 1 ;←データaのアドレスを1加算
loop LOOP1 ;←ecxの回数分ループ
というのを、
rep movsb
という、たった1行で行なってくれる便利な命令なのです。
そして、この便利な「rep」命令等の事をインテルプロセッサ
では「リピートプリフィックス命令」と総称し、「movsb」命
令等の事は「ストリング命令」と総称して呼びます。
ここで出てきた例では、「rep」命令と「movsb」命令を使いま
したが、ストリング・リピートプリフィックス命令は他にもあ
り、32ビットのデータを転送する事や16ビットのデータを
転送する事等も出来ます。
● ●
● ビルドする ●
● ●
コマンドプロンプト上で以下の様に入力してください。
sc rep.c -j
これでビルドされ、"rep.exe"という実行ファイルが作成され
るはずです。
● ●
● 実行する ●
● ●
コマンドプロンプト上で以下の様に入力してください。
rep.exe
これでサブ関数を呼び出す前のデータaとデータbの中身と、サ
ブ関数を呼び出した後のデータaとデータbの中身がそれぞれ表
示されたはずです。
前回の実行結果と同じなのであまり面白味がないかもしれませ
んが、前回のプログラムよりは命令数が大幅に少なくなってい
る事を考えると少しはへぇー、と思いますよね?
今回はインテルプロセッサの「ストリング・リピートプリフィ
ックス命令」を使用しました。
インテルプロセッサのストリング・リピートプリフィックス命
令の様に、たった1行の命令で複数の事を行ってくれる命令を
備えたプロセッサの事を「CISC(シスク)プロセッサ」と呼び
ます。
CISCとは、「Complex Instruction Set Computer」(複合命令
セットコンピュータ)の略です。
少ない命令数でさまざまな事を行ってくれるので便利な事も多
いのですが、その代わりプロセッサの設計が複雑な物となって
しまい、トランジスタ数が増えてしまったりします。
これに対して、「RISC(リスク)プロセッサ」というのもあり
ます。
RISCとは、「Reduced Instruction Set Computer」(単純命令
セットコンピュータ)の略です。
CISCプロセッサの様な複雑な事を行う命令を極力排除し、単純
な命令の組み合わせだけでプログラムを組めるようにしたプロ
セッサの事です。
現在の、インテル以外のプロセッサのほとんどがRISCプロセッ
サになります。
今回はデータをコピーするプログラムを効率良くしてみました。
次回は、これらのデータを加工してみる予定です。