サイクルタイムを測定しよう (11) [FMx]
前回は、最小ループのサイクル数を測定しました。 今回は、ループの配置アドレスによってサイクル数に差が出るかについて調べました。
ソースコード
配置アドレスを変更する考え方は、 PSoC で行った方法と同じです。 ループの前に "nop" 命令を追加して、ループのアドレスを移動します。 以下のコードで、 "nop" 命令の数を調整します。
void func9(reg8_t *reg, uint8_t val0, uint8_t val1) @ ".text.func9" { __asm( "nop\n" // 29 "nop\n" // 28 "nop\n" // 27 "nop\n" // 26 "nop\n" // 25 "nop\n" // 24 "nop\n" // 23 "nop\n" // 22 "nop\n" // 21 "nop\n" // 20 "nop\n" // 19 "nop\n" // 18 "nop\n" // 17 "nop\n" // 16 "nop\n" // 15 "nop\n" // 14 "nop\n" // 13 "nop\n" // 12 "nop\n" // 11 "nop\n" // 10 "nop\n" // 9 "nop\n" // 8 "nop\n" // 7 "nop\n" // 6 "nop\n" // 5 "nop\n" // 4 "nop\n" // 3 "nop\n" // 2 "nop\n" // 1 "label_1:" ); for (;;) { *reg = val0; *reg = val1; } }
func9() 関数は、 @ 指示子によって、セクション名が決められています。 このセクション名を "icf" ファイルで指定する事で、 func9() 関数の境界を定めることが出来ます。
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; define block FUNC9 with alignment = 32 { section ".text.func9" }; define block MAIN with alignment = 32 { section ".text.main" }; : : place in ROM_region { readonly, block FUNC9, block MAIN };
このプロジェクトの場合、上記の記述が入っています。 "define block" でブロック名を定義します。 FUNC9 ブロックには ".text.func9" セクションが入っており、 alignment を 32 と定義しています。 この記述により、 func9() 関数は 32 バイト境界に配置されます。
測定結果
サイクル数を測定した所、周期的に4サイクルと6サイクルのパターンを繰り返す事がわかりました。
NOP数 | サイクル数 | 分岐先アドレス | 分岐命令 |
---|---|---|---|
0 | 4 | 02 | 06 |
1 | 4 | 04 | 08 |
2 | 4 | 06 | 0A |
3 | 4 | 08 | 0C |
4 | 4 | 0A | 0E |
5 | 6 | 0C | 10 |
6 | 6 | 0E | 12 |
7 | 4 | 10 | 14 |
8 | 4 | 12 | 16 |
9 | 4 | 14 | 18 |
10 | 4 | 16 | 1A |
11 | 4 | 18 | 1C |
12 | 4 | 1A | 1E |
13 | 6 | 1C | 20 |
14 | 6 | 1E | 22 |
15 | 4 | 20 | 24 |
16 | 4 | 22 | 26 |
17 | 4 | 24 | 28 |
18 | 4 | 26 | 2A |
19 | 4 | 28 | 2C |
20 | 4 | 2A | 2E |
21 | 6 | 2C | 30 |
22 | 6 | 2E | 32 |
23 | 4 | 30 | 34 |
24 | 4 | 32 | 36 |
25 | 4 | 34 | 38 |
26 | 4 | 36 | 3A |
27 | 4 | 38 | 3C |
28 | 4 | 3A | 3E |
29 | 6 | 3C | 40 |
サイクル数が6サイクルになるのは、分岐先アドレスの下4ビットが 11xx になるときです。 このとき、分岐先のアドレスと分岐命令アドレスの上位部分が異なっているのがわかります。 例えば、 NOP 数が 5 の時、分岐先アドレスの上位4ビットは 0000 ですが、分岐命令アドレスの上位4ビットは 0001 です。 このように、分岐先と分岐命令が16バイト境界を超えるとサイクル数が増えます。
これは、16バイト境界を超えると分岐先命令をフェッチするために追加サイクルが必要になり、サイクル数が伸びたと考えられます。 また、 Flash ROM のフェッチバッファのサイズは16バイトであるとも推測できます。
ひとつだけ腑に落ちない点もあります。 例えば、 NOP数が 4 の時、分岐命令は 0E にあります。 分岐命令が実行される時、命令がプリフェッチされているのであれば、バッファには 10 から 17 までの内容がロードされているはずです。 その場合、分岐先の命令がバッファに入っていないので、当然、再度フェッチが発生し、サイクル数が伸びるはずです。 しかし、実際には、4サイクルのままです。 この事実から推測されるのは、分岐実行の前にプリフェッチが行われていないのか、プリフェッチバッファが多数存在するかのどちらかです。 この測定結果からは、どちらとも言えません。
コメント 0