サイクルタイムを測定しよう (5) [PSoC]
今回は、分岐命令の実行サイクルタイムを測定します。
分岐命令を入れる
前回の記事で、 "nop" 命令を入れた所に "b" 命令を入れます。
uint32 s; uint32 e; s = *reg; asm( "b label_2\n" "label_2:\n" ); e = *reg;
分岐先は、 "label_2" ラベルで指示します。 まずは、次の命令に分岐した場合について調べます。
このプログラムをコンパイルすると、このようなコードが生成されます。
39:.\main.c **** uint32 s; 40:.\main.c **** uint32 e; 41:.\main.c **** 59:.\main.c **** s = *reg; 95 0000 0268 ldr r2, [r0] 60:.\main.c **** asm( 99 0002 FFE7 b label_2 100 label_2: 61:.\main.c **** "b label_2\n" 72:.\main.c **** "label_2:\n" 73:.\main.c **** ); 74:.\main.c **** e = *reg; 105 0004 0368 ldr r3, [r0]
次の命令に分岐するという事は、動作としては "nop" と変わりありません。 ところが、サイクルタイムは7サイクルと表示されました。
Freq:48 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 Freq:24 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 Freq:12 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007
つまり、分岐命令に要したのは、3サイクルという計算になります。 この結果から、分岐命令の処理に3サイクル必要だと判断できます。
命令の配置アドレスを変えてみた
ところが、いかなる場合でも3サイクルになったわけではありませんでした。 分岐命令の配置アドレスによって、サイクルタイムが変わってきたのです。
39:.\main.c **** uint32 s; 40:.\main.c **** uint32 e; 41:.\main.c **** 42:.\main.c **** asm( 90 0000 C046 nop 91 0002 C046 nop 92 0004 C046 nop 93 0006 C046 nop 94 label_1: 95 53:.\main.c **** "nop\n" // 4 54:.\main.c **** "nop\n" // 3 55:.\main.c **** "nop\n" // 2 56:.\main.c **** "nop\n" // 1 57:.\main.c **** "label_1:\n" 58:.\main.c **** ); 59:.\main.c **** s = *reg; 99 0008 0268 ldr r2, [r0] 60:.\main.c **** asm( 103 000a FFE7 b label_2 104 label_2: 105 61:.\main.c **** "b label_2\n" 72:.\main.c **** "label_2:\n" 73:.\main.c **** ); 74:.\main.c **** e = *reg; 109 000c 0368 ldr r3, [r0]
例えば、このプログラムでは、先頭に "nop" 命令を4個挿入して、コードの位置を8バイト後ろにずらしました。 すると、以下のように表示されました。
Freq:48 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 0009 Freq:24 0008 0008 0008 0008 0008 0008 0008 0008 0008 0008 0008 0008 0008 0008 0008 0008 Freq:12 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007 0007
このようにバス周波数によってサイクル数が異なっている原因は、 Flash ROM のウェイトサイクルが影響しているものと推測されます。 挿入する "nop" 命令の数を変えながらサイクル数を測定したのが、以下の表です。
NOP数 | サイクル数 48/24/12 | 分岐先アドレス |
---|---|---|
0 | 7/7/7 | 0004 |
1 | 7/7/7 | 0006 |
2 | 7/7/7 | 0008 |
3 | 7/7/7 | 000A |
4 | 9/8/7 | 000C |
5 | 9/8/7 | 000E |
6 | 7/7/7 | 0010 |
7 | 7/7/7 | 0012 |
8 | 9/8/7 | 0014 |
9 | 9/8/7 | 0016 |
10 | 7/7/7 | 0018 |
11 | 7/7/7 | 001A |
12 | 9/8/7 | 001C |
13 | 9/8/7 | 001E |
14 | 7/7/7 | 0020 |
このように NOP 命令が4個(8バイト)増えるごとにサイクルタイムの長いパターンが発生します。 この結果から、プリフェッチバッファは、8バイトで構成されているらしいことが推測されます。 さらに分岐先アドレスに着目すると、飛び先アドレスの LSB 部分が X1X0 であった場合に限りサイクルタイムが長くなっている事がわかります。 これは、8バイトバッファの後半に分岐した場合には、次の8バイトのプリフェッチが追加されているものと推測されます。
今回の実験で、分岐命令の分岐先のアドレスにより、必要なサイクル数が異なってくるらしい事がわかってきました。 実験で見えてきた違いは、1サイクルまたは2サイクルです。 このくらいだったら気にすることも無いですかね。
コメント 0