サイクルタイムを測定しよう (3) [PSoC]
タイマを使用して、サイクルタイムを測定するしかけができたので、具体的にサイクルタイムを測定していきます。 今回は、命令フェッチのサイクル数にこだわってみます。
測定ルーチンをちょっと変更
前回の記事では、 measure() 関数の中でカウンタレジスタを直接読み出していました。 そのため、以下のように .L5 に格納されたカウンタレジスタのアドレスを CPU のレジスタ r3 に格納する命令が入ってしまいます。
38:.\main.c **** uint32 s; 39:.\main.c **** uint32 e; 40:.\main.c **** 41:.\main.c **** s = Timer_COUNTER_REG; 88 0000 024B ldr r3, .L5 89 0002 1868 ldr r0, [r3] : : 43:.\main.c **** e = Timer_COUNTER_REG; 92 0004 1B68 ldr r3, [r3] 44:.\main.c **** 45:.\main.c **** return e - s; 95 0006 181A sub r0, r3, r0 46:.\main.c **** } 98 @ sp needed 99 0008 7047 bx lr : : 102 .L5: 103 000c 08012040 .word 1075839240
インストラクションもレジスタアドレスも Flash ROM に格納されますので、レジスタアドレスの取り出しが命令フェッチに影響を与える可能性があります。 そこで、レジスタアドレスを関数の引数として渡す方式に改めました。
// Measure the execution cycle time uint32 measure(reg32 *reg) __attribute__((aligned(256))); uint32 measure(reg32 *reg) { uint32 s; uint32 e; s = *reg; : : e = *reg; return e - s; } : : // Measure the cycle time for (i = 0; i < N_DIFF; i++) { diffs[i] = measure(Timer_COUNTER_PTR) & Timer_16BIT_MASK; }
こうすると、レジスタアドレスは CPU のレジスタに格納されたまま使用されます。
39:.\main.c **** uint32 s; 40:.\main.c **** uint32 e; 41:.\main.c **** 42:.\main.c **** s = *reg; 89 0000 0268 ldr r2, [r0] : : 43:.\main.c **** e = *reg; 92 0002 0368 ldr r3, [r0]
また、 "aligned(256)" という属性を追加して、関数の配置アドレスがブレないようにしています。
レジスタ読み出しが連続した場合
まず、タイマレジスタのアクセスが連続した場合について調べます。
42:.\main.c **** s = *reg; 89 0000 0268 ldr r2, [r0] 43:.\main.c **** e = *reg; 92 0002 0368 ldr r3, [r0]
この場合、タイマカウンタの値の差分をとると、 "ldr" 命令一回分のサイクル数を求めることが出来ます。 UART への出力は、以下のようになりました。
Freq:48 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 Freq:24 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 Freq:12 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004 0004
CPU の周波数が変わっても4サイクルでした。 もしかしたら、プログラムの配置アドレスに依存するかもしれないと考えて、これらの前に "nop" 命令を入れて、配置を変更してみました。
asm( "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:\n" ); s = *reg; e = *reg;
結果は、いずれの場合も4サイクルのままでした。 PSoC 4 の Flash ROM は、バス周波数が高くなる場合には最大2サイクルのウェイトサイクルが入ります。 しかし、いずれのバス周波数の場合でも同じサイクル数を示しています。 これは、 Flash ROM から読み出した命令を先読みするプリフェッチ機構が存在するためです。 プリフェッチのおかげで、命令を連続して実行する場合には、 Flash ROM のアクセス時間が見えなくなります。
コメント 0