SSブログ

サイクルタイムを測定しよう (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 のアクセス時間が見えなくなります。


nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。