FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

CPUのテストパタンを自動生成する方式の検討

趣味でRISC-VのCPUコアを設計しているのだが、デバッグおよび性能検証を行うためのパタンが必要になる。 様々なアプリケーションを使って検証すれば良いのだが、網羅的かどうかも分からない。また、基本的な命令セットの性能検証も行う必要がありそうだ。

そういう意味では、定義した命令毎に性能検証を行う必要がありそうだ。このためには、あらかじめ定義したISSの命令テーブルを使ってテストパタンを自動生成できるかもしれない。

命令発行幅を確認するためのテストパタンを自動生成する方式の検討

$arch_table[  0] = Array['lui        d[11:7],h[31:12]',                   'XXXXX', 'XX',     'XXXXX', 'XXXXX', 'XXX',    'XXXXX', '0110111', Array['OP']                                    , 'ALU', Array['RD_R3',          'OP_S
$arch_table[  1] = Array['auipc      d[11:7],h[31:12]',                   'XXXXX', 'XX',     'XXXXX', 'XXXXX', 'XXX',    'XXXXX', '0010111', Array['OP']                                    , 'ALU', Array['R1_PC', 'RD_R3', 'OP_S
$arch_table[  2] = Array['jal        d[11:7],uj[31:12]',                  'XXXXX', 'XX',     'XXXXX', 'XXXXX', 'XXX',    'XXXXX', '1101111', Array['OP']                                    , 'BRU', Array['RD_R3',
$arch_table[  3] = Array['jalr       d[11:7],d[19:15],h[11:0]',           'XXXXX', 'XX',     'XXXXX', 'XXXXX', '000',    'XXXXX', '1100111', Array['OP']                                    , 'BRU', Array['RD_R3', 'R1_R1'
$arch_table[  4] = Array['beq        d[19:15],d[24:20],sb[31:25]',        'XXXXX', 'XX',     'XXXXX', 'XXXXX', '000',    'XXXXX', '1100011', Array['OP', 'F3']                              , 'BRU', Array['R1_R1', 'R2_R2', 'OP_S
$arch_table[  5] = Array['bne        d[19:15],d[24:20],sb[31:25]',        'XXXXX', 'XX',     'XXXXX', 'XXXXX', '001',    'XXXXX', '1100011', Array['OP', 'F3']                              , 'BRU', Array['R1_R1', 'R2_R2', 'OP_S```

命令テーブルは上記のように定義されている。ここで、auipc d[11:7],h[31:12]d[11:7]レジスタの定義を示している。 この部分をアセンブリ言語に変換して、該当命令を生成させれば良い。 自動生成するのは以下のような構造をしたC言語のプログラムだ。

for (i = 0; i < 32; i++) {
  ターゲット命令
  ターゲット命令
  ターゲット命令
  ターゲット命令
  ターゲット命令
  ターゲット命令
  ターゲット命令
}

volatile asm の使用

欲しい命令を生成するためには、Cプログラム中にvolatile asmを挿入すれば良い。

    asm volatile ("add t0,t1,t2")

ここでレジスタを直接指定すると、間違ってレジスタを書き潰してしまうかもしれない。 そこで、asm volatileの拡張表現を使用しよう。

d.hatena.ne.jp

  int32_t out0;
  int32_t in0_0 = 308;
  int32_t in0_1 = 928;

  asm volatile ("add        %0,%1,%2"
      :"=r"(out0)
      :"r"(in0_0),"r"(in0_1)
      :

asm volatileの構文は以下のようになる。

asm volatile ("命令ニーモニック"
   : 書き込みが発生するレジスタ
   : 読み込みが発生するレジスタ
   : 暗黙的に書き込みレジスタ(フラグなど)

書き込みが発生するレジスタは、"=r"(out0)として記述している。rは汎用レジスタであることを示し、out0はそれに該当する変数である。 また、読み込みが発生するレジスタ"r"(in0_0),"r"(in0_1) として記述している。in0_0in0_1はそれに該当する変数である。

生成されたC言語プログラム

以下のような実装を行った。

github.com

例えば、add命令は以下のようになる。

int main () {
  int32_t out0;
  int32_t in0_0 = 308;
  int32_t in0_1 = 928;
  int32_t out1;
  int32_t in1_0 = 156;
  int32_t in1_1 = 494;
  int32_t out2;
  int32_t in2_0 = 21;
...
  for (i = 0; i < 32; i++) {
    asm volatile ("add        %0,%1,%2"
      :"=r"(out0)
      :"r"(in0_0),"r"(in0_1)
      :
      );
    asm volatile ("add        %0,%1,%2"
      :"=r"(out1)
      :"r"(in1_0),"r"(in1_1)
      :
      );
    asm volatile ("add        %0,%1,%2"
      :"=r"(out2)
      :"r"(in2_0),"r"(in2_1)
      :
      );
    asm volatile ("add        %0,%1,%2"
      :"=r"(out3)
      :"r"(in3_0),"r"(in3_1)
      :
      );
    asm volatile ("add        %0,%1,%2"
      :"=r"(out4)
      :"r"(in4_0),"r"(in4_1)
      :
      );
    asm volatile ("add        %0,%1,%2"
      :"=r"(out5)
      :"r"(in5_0),"r"(in5_1)
      :
      );
    asm volatile ("add        %0,%1,%2"
      :"=r"(out6)
      :"r"(in6_0),"r"(in6_1)
      :
      );
    asm volatile ("add        %0,%1,%2"
      :"=r"(out7)
      :"r"(in7_0),"r"(in7_1)
      :
      );
  }
...

add命令を8個並べた。コンパイル後は以下のようになった。-O3を使っているので、アンローリングされている。

 310:   1d400713                li      a4,468
 314:   03c00793                li      a5,60
 318:   00740933                add     s2,s0,t2
 31c:   01f28933                add     s2,t0,t6
 320:   01df0933                add     s2,t5,t4
 324:   006e0933                add     s2,t3,t1
 328:   01088933                add     s2,a7,a6
 32c:   00b50933                add     s2,a0,a1
 330:   00d60933                add     s2,a2,a3
 334:   00f70933                add     s2,a4,a5
 338:   00740933                add     s2,s0,t2
 33c:   01f28933                add     s2,t0,t6
 340:   01df0933                add     s2,t5,t4
 344:   006e0933                add     s2,t3,t1
 348:   01088933                add     s2,a7,a6
 34c:   00b50933                add     s2,a0,a1
 350:   00d60933                add     s2,a2,a3
 354:   00f70933                add     s2,a4,a5
 358:   00740933                add     s2,s0,t2
 35c:   01f28933                add     s2,t0,t6
 360:   01df0933                add     s2,t5,t4
 364:   006e0933                add     s2,t3,t1
 368:   01088933                add     s2,a7,a6
 36c:   00b50933                add     s2,a0,a1
 370:   00d60933                add     s2,a2,a3
 374:   00f70933                add     s2,a4,a5
 378:   00740cb3                add     s9,s0,t2
 37c:   01f28c33                add     s8,t0,t6
 380:   01df0bb3                add     s7,t5,t4
 384:   006e0b33                add     s6,t3,t1
 388:   01088ab3                add     s5,a7,a6
 38c:   00b50a33                add     s4,a0,a1
 390:   00d609b3                add     s3,a2,a3
 394:   00f70933                add     s2,a4,a5
 398:   ffc48493                addi    s1,s1,-4
 39c:   f6049ee3                bnez    s1,318 <main+0x70>

これを開発中のRISC-VのCPU実装で実行すると、パイプラインは以下のようになった。一応、想定通りの性能が得られている。

   |    ||                                                                                 |                                                                                 |
   |    ||                                                                                 |                                                                                 |
   |    ||(Cm36,D32)[PC=000002a8] R 2<=000043c8 : ADDI      r 2,r 2,0xfd0       ( 3)     36|                                                                                 |
   |    ||(Cm37,D--)[PC=000002ac]               : SW        r 8,0x02c,r 2                37|                                                                                 |
   |    ||(Cm38,D--)[PC=000002b0]               : SW        r 9,0x028,r 2                38|                                                                                 |
   |    ||(Cm39,D--)[PC=000002b4]               : SW        r18,0x024,r 2                39|                                                                                 |
   |    ||(Cm40,D--)[PC=000002b8]               : SW        r19,0x020,r 2                40|                                                                                 |
   |    ||(Cm41,D--)[PC=000002bc]               : SW        r20,0x01c,r 2                41|                                                                                 |
   |    ||(Cm42,D--)[PC=000002c0]               : SW        r21,0x018,r 2                42|                                                                                 |
   |    ||(Cm43,D--)[PC=000002c4]               : SW        r22,0x014,r 2                43|                                                                                 |
b47|    ||(Cm44,D--)[PC=000002c8]               : SW        r23,0x010,r 2                44|                                                                                 |
b49|    ||(Cm45,D--)[PC=000002cc]               : SW        r24,0x00c,r 2                45|                                                                                 |
b51|    ||(Cm46,D--)[PC=000002d0]               : SW        r25,0x008,r 2                46|(Cm47,D35)[PC=000002d4] R 9<=00000020 : ADDI      r 9,r 0,0x020       (10)     47|(Cm48,D36)[PC=000002d8] R 8<=00000317 : ADDI      r
b53|    ||(Cm50,D38)[PC=000002e0] R 5<=00000279 : ADDI      r 5,r 0,0x279       ( 6)     50|(Cm51,D39)[PC=000002e4] R31<=000001b1 : ADDI      r31,r 0,0x1b1       (34)     51|(Cm52,D40)[PC=000002e8] R30<=00000377 : ADDI      r3
b55|    ||(Cm53,D41)[PC=000002ec] R29<=000002b9 : ADDI      r29,r 0,0x2b9       (30)     53|(Cm54,D42)[PC=000002f0] R28<=0000038a : ADDI      r28,r 0,0x38a       (29)     54|
b57|    ||(Cm55,D43)[PC=000002f4] R 6<=0000032f : ADDI      r 6,r 0,0x32f       ( 7)     55|(Cm56,D44)[PC=000002f8] R17<=00000161 : ADDI      r17,r 0,0x161       (18)     56|
b59|    ||(Cm57,D45)[PC=000002fc] R16<=0000017d : ADDI      r16,r 0,0x17d       (17)     57|(Cm58,D46)[PC=00000300] R10<=00000159 : ADDI      r10,r 0,0x159       (11)     58|
b61|    ||(Cm59,D47)[PC=00000304] R11<=00000165 : ADDI      r11,r 0,0x165       (12)     59|(Cm60,D48)[PC=00000308] R12<=0000023d : ADDI      r12,r 0,0x23d       (13)     60|
b63|    ||(Cm61,D49)[PC=0000030c] R13<=00000207 : ADDI      r13,r 0,0x207       (14)     61|(Cm62,D50)[PC=00000310] R14<=000002bc : ADDI      r14,r 0,0x2bc       (15)     62|
b 1|    ||(Cm63,D51)[PC=00000314] R15<=000000a7 : ADDI      r15,r 0,0x0a7       (16)     63|(Cm 0,D52)[PC=00000318] R18<=0000060a : ADD       r18,r 8,r 7         (19)     64|
b 3|    ||(Cm 1,D53)[PC=0000031c] R18<=0000042a : ADD       r18,r 5,r31         (52)     65|(Cm 2,D54)[PC=00000320] R18<=00000630 : ADD       r18,r30,r29         (53)     66|
b 5|    ||(Cm 3,D55)[PC=00000324] R18<=000006b9 : ADD       r18,r28,r 6         (54)     67|(Cm 4,D56)[PC=00000328] R18<=000002de : ADD       r18,r17,r16         (55)     68|
b 7|    ||(Cm 5,D57)[PC=0000032c] R18<=000002be : ADD       r18,r10,r11         (56)     69|(Cm 6,D58)[PC=00000330] R18<=00000444 : ADD       r18,r12,r13         (57)     70|
b 9|    ||(Cm 7,D59)[PC=00000334] R18<=00000363 : ADD       r18,r14,r15         (58)     71|(Cm 8,D60)[PC=00000338] R18<=0000060a : ADD       r18,r 8,r 7         (59)     72|
b11|    ||(Cm 9,D61)[PC=0000033c] R18<=0000042a : ADD       r18,r 5,r31         (60)     73|(Cm10,D62)[PC=00000340] R18<=00000630 : ADD       r18,r30,r29         (61)     74|
b13|    ||(Cm11,D 9)[PC=00000344] R18<=000006b9 : ADD       r18,r28,r 6         (62)     75|(Cm12,D 0)[PC=00000348] R18<=000002de : ADD       r18,r17,r16         ( 9)     76|
b15|    ||(Cm13,D 4)[PC=0000034c] R18<=000002be : ADD       r18,r10,r11         ( 0)     77|(Cm14,D 3)[PC=00000350] R18<=00000444 : ADD       r18,r12,r13         ( 4)     78|
b17|    ||(Cm15,D10)[PC=00000354] R18<=00000363 : ADD       r18,r14,r15         ( 3)     79|(Cm16,D33)[PC=00000358] R18<=0000060a : ADD       r18,r 8,r 7         (10)     80|
b19|    ||(Cm17,D 8)[PC=0000035c] R18<=0000042a : ADD       r18,r 5,r31         (33)     81|(Cm18,D 6)[PC=00000360] R18<=00000630 : ADD       r18,r30,r29         ( 8)     82|
b21|    ||(Cm19,D34)[PC=00000364] R18<=000006b9 : ADD       r18,r28,r 6         ( 6)     83|(Cm20,D31)[PC=00000368] R18<=000002de : ADD       r18,r17,r16         (34)     84|
b23|    ||(Cm21,D30)[PC=0000036c] R18<=000002be : ADD       r18,r10,r11         (31)     85|(Cm22,D29)[PC=00000370] R18<=00000444 : ADD       r18,r12,r13         (30)     86|
b25|    ||(Cm23,D 7)[PC=00000374] R18<=00000363 : ADD       r18,r14,r15         (29)     87|(Cm24,D18)[PC=00000378] R25<=0000060a : ADD       r25,r 8,r 7         (26)     88|
b27|    ||(Cm25,D17)[PC=0000037c] R24<=0000042a : ADD       r24,r 5,r31         (25)     89|(Cm26,D11)[PC=00000380] R23<=00000630 : ADD       r23,r30,r29         (24)     90|
b29|    ||(Cm27,D12)[PC=00000384] R22<=000006b9 : ADD       r22,r28,r 6         (23)     91|(Cm28,D13)[PC=00000388] R21<=000002de : ADD       r21,r17,r16         (22)     92|
b31|    ||(Cm29,D14)[PC=0000038c] R20<=000002be : ADD       r20,r10,r11         (21)     93|(Cm30,D15)[PC=00000390] R19<=00000444 : ADD       r19,r12,r13         (20)     94|
   |    ||(Cm31,D16)[PC=00000394] R18<=00000363 : ADD       r18,r14,r15         ( 7)     95|(Cm32,D19)[PC=00000398] R 9<=0000001c : ADDI      r 9,r 9,0xffc       (35)     96|
   |    ||(Cm33,D--)[PC=0000039c]               : BNE       r 9,r 0,0x7b                 97|                                                                                 |
   |    ||                                                                                 |                                                                                 |
-- FLUSH --------------- FLUSH --------------- FLUSH --------------- FLUSH --------------- FLUSH --------------- FLUSH --------------- FLUSH --------------- FLUSH --------------- FLUSH --------------- FLUSH --------------- FLU
   |    ||                                                                                 |                                                                                 |
   |    ||                                                                                 |                                                                                 |
   |    ||                                                                                 |                                                                                 |