FPGA開発日記

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

LiteXによるSoC環境構築を試行する (21. ILAを使ったデバッグ)

0x28付近でループしている。これは例外処理の部分。

0000000000000020 <trap_entry>:
      20:       fe113c23                sd      ra,-8(sp)
      24:       fe513823                sd      t0,-16(sp)
      28:       fe613423                sd      t1,-24(sp)
      2c:       fe713023                sd      t2,-32(sp)
      30:       fca13c23                sd      a0,-40(sp)
      34:       fcb13823                sd      a1,-48(sp)
      38:       fcc13423                sd      a2,-56(sp)
      3c:       fcd13023                sd      a3,-64(sp)
      40:       fae13c23                sd      a4,-72(sp)
      44:       faf13823                sd      a5,-80(sp)
      48:       fb013423                sd      a6,-88(sp)
      4c:       fb113023                sd      a7,-96(sp)
      50:       f9c13c23                sd      t3,-104(sp)
      54:       f9d13823                sd      t4,-112(sp)
      58:       f9e13423                sd      t5,-120(sp)
      5c:       f9f13023                sd      t6,-128(sp)
      60:       f8010113                add     sp,sp,-128
      64:       78d030ef                jal     3ff0 <isr>
      68:       07813083                ld      ra,120(sp)
      6c:       07013283                ld      t0,112(sp)
      70:       06813303                ld      t1,104(sp)
      74:       06013383                ld      t2,96(sp)
      78:       05813503                ld      a0,88(sp)
      7c:       05013583                ld      a1,80(sp)
      80:       04813603                ld      a2,72(sp)
      84:       04013683                ld      a3,64(sp)
      88:       03813703                ld      a4,56(sp)
      8c:       03013783                ld      a5,48(sp)
      90:       02813803                ld      a6,40(sp)
      94:       02013883                ld      a7,32(sp)
      98:       01813e03                ld      t3,24(sp)
      9c:       01013e83                ld      t4,16(sp)
      a0:       00813f03                ld      t5,8(sp)
      a4:       00013f83                ld      t6,0(sp)
      a8:       08010113                add     sp,sp,128
      ac:       30200073                mret

ずっと割り込みルーチンを回っている気がする。

0xac → 0x20 をずっと回っている気がする。

なんで0x64の飛び先が毎回変わっているんだ?

左のobjdumpでは、0x64が0x3ff0に飛んでいるが、initファイルは、

fb013423
fb113023
f9c13c23
f9d13823
f9e13423
f9f13023
f8010113
2e8040ef  # 0x64 ずれている?
07813083
07013283
06813303
06013383
05813503
05013583
04813603

なんでこれがずれるんだ?

再合成して、もう一度アセンブリコードを作り直し:

mretからの戻りが、0x10001ef8などという意味不明なアドレスからになっている。

0xac(mret)からの戻りが、どうして0x20になっているのだろう?

なんか、0x41d8の0xc002000への書き込みの時に例外が発生しているっポイ?

    41d4:       ffc6f813                and     a6,a3,-4
    41d8:       01062023                sw      a6,0(a2)
    41dc:       31c72603                lw      a2,796(a4)
    41e0:       3205a703                lw      a4,800(a1)
    41e4:       00e61a63                bne     a2,a4,41f8 <uart_write+0x54>
    41e8:       12003637                lui     a2,0x12003

0x41d8で、ST例外が発生しているようだが、tvalが0になっている。アドレス計算に失敗している?

レジスタの読み出し状況をチェックする必要がある。

オープンソースの波形ビューワSurferを試す

少し前に話題になっていたけれども、Rustで記述されたオープンソースの波形ビューワのSurferについていろいろ試行していた。

surfer-project / surfer · GitLab

これまでは基本的に波形ビューワとしてGTKwaveを使っていたのだけれども、どうにもGTKwaveも使いにくいので、こちらも試行してみようと思う。

とりあえずリリースビルドのダウンロードしてきたものは、wellenというfst読み込み用のライブラリが古くて、自作CPUの出力したfstが読み込めなかったので、wellenだけをバージョンアップしてローカルでWindows用に再ビルドした。

とりあえず、手元のfstを読み込むことができることを確認した。

ちなみに、URLを指定して波形を読み込むことができる。ただしこれはやってみると波形ファイルをダウンロードするようだ。 ダウンロードに必要な時間が生じるのは変わらない。

なるほど、波形ビューワの分割とかもできるんだな。

もうちょっとほしい機能としては、波形の複数選択とかなな。

LiteXのUART書き込みのフローについて

LiteXにおけるUARTの書き込みについて、そのフローを確認しておく。

  • litex/litex/soc/software/libc/stdio.c
static int
litex_putc(char c, FILE *file)
{
    (void) file; /* Not used in this function */
#ifdef CSR_UART_BASE
    uart_write(c);
    if (c == '\n')
        litex_putc('\r', NULL);
#endif
    return c;
}

uart_write()を呼び出す。

  • litex/litex/soc/software/libbase/uart.c

ポイントは、IRQにおけるUART_INTERRUPTをDisableにして、tx_bufに文字を書き込んでいく。 書き込んだ後に、irqmaskを書き込み直して、割り込みを発生させる。 書き込みバッファにすでに値が入ってれば、バッファを更新する。そうでなければ、uart_rxtx_write(c)を直接書き込む。

void uart_write(char c)
{
    unsigned int oldmask;
    unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;

    if(irq_getie()) {
        while(tx_produce_next == tx_consume);
    } else if(tx_produce_next == tx_consume) {
        return;
    }

    oldmask = irq_getmask();
    irq_setmask(oldmask & ~(1 << UART_INTERRUPT));
    if((tx_consume != tx_produce) || uart_txfull_read()) {
        tx_buf[tx_produce] = c;
        tx_produce = tx_produce_next;
    } else {
        uart_rxtx_write(c);
    }
    irq_setmask(oldmask);
}

このuart_rxtx_write()が実際にUARTのモジュールに書き込みを行う。

static inline void uart_rxtx_write(uint32_t v) {
    csr_write_simple(v, (CSR_BASE + 0x3000L));
}

LiteXによるSoC環境構築を試行する (20. ILAを使ったデザインのデバッグ)

LiteXのLiteScopeではどうにも細かい信号を取得することができないので、Xilinxの純正の波形のデバッグツールであるILA(Integrated Logic Analyzer)を使って内部の信号を観察する方法を見てみる。

一応、一歩ずつ問題を特定しているが、まだまだ動いていない。 分岐命令のオペランドがReadyにならずに、命令がデッドロックしている。 一応リネーム・マップを確認すると、Readyになっているのでこれがうまく伝搬していない。

Freelistに32が2回Popされている。

0x154がDEAD状態になって物理ID=32をフリーリストに返却する。 さらに、新たなるフェッチ(ID=23)が物理ID=58を取得するが、その時に古い物理ID=32が通知されている。 これは、Rename-Mapにまだ物理ID=32が残っており、どうもそれを取得しているっぽい?

LiteXによるSoC環境構築を試行する (20. ILAを使ったデザインのデバッグ)

LiteXのLiteScopeではどうにも細かい信号を取得することができないので、Xilinxの純正の波形のデバッグツールであるILA(Integrated Logic Analyzer)を使って内部の信号を観察する方法を見てみる。

一応、一歩ずつ問題を特定しているが、まだまだ動いていない。 分岐命令のオペランドがReadyにならずに、命令がデッドロックしている。 一応リネーム・マップを確認すると、Readyになっているのでこれがうまく伝搬していない。

これも要解析だな。

LiteXによるSoC環境構築を試行する (19. ILAを使ったデザインのデバッグ)

LiteXのLiteScopeではどうにも細かい信号を取得することができないので、Xilinxの純正の波形のデバッグツールであるILA(Integrated Logic Analyzer)を使って内部の信号を観察する方法を見てみる。

もうちょっと細かい信号を取得するために、tclでILAを挿入する場所を細かく変えながらいろいろ動作を取得している。

以下のようなtclファイルを用意して、取得したい信号をILAに挿入する。

# BRU dispatch
set bru_net_lists {
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_issue_unit/w_entry_valid.*"
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_issue_unit/w_entry_ready.*"
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_issue_unit/entry_loop.0..u_issue_entry/r_state.*"
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_issue_unit/entry_loop.1..u_issue_entry/r_state.*"
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_issue_unit/entry_loop.0..u_issue_entry/r_entry.*"
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_issue_unit/entry_loop.1..u_issue_entry/r_entry.*"
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_bru_pipe/w_ex0_issue.*"
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_bru_pipe/r_ex1_issue.*"
    "mycpu_subsystem_axi_wrapper/u_mycpu_subsystem/u_tile/u_bru/u_bru_pipe/r_ex2_issue.*"
    }
foreach net $bru_net_lists {
    set debug_nets [lsort -dictionary [get_nets -hierarchical -regexp $net]]
    puts $debug_nets
    set new_port [create_debug_port u_ila_0 probe]
    set_property port_width [llength $debug_nets] [get_debug_ports $new_port]
    set_property PROBE_TYPE DATA_AND_TRIGGER $new_port
    connect_debug_port $new_port $debug_nets
}

必要な信号部分は、Vivadoでの最適化を抑制するためのアトリビュートを挿入する必要がある。

(* mark_debug="true" *)(* dont_touch="yes" *) scariv_bru_pkg::issue_entry_t            w_ex0_issue;

論理合成を最初からやり直しているのでそれぞれのイタレーションは30分~1時間くらいかかってしまうが、仕方がない。 これで、少しずつ命令がデッドロックしてしまう原因を特定している。時間はかかるが、もう少しだ。

LiteXによるSoC環境構築を試行する (18. ILAを使ったデザインのデバッグ)

LiteXのLiteScopeではどうにも細かい信号を取得することができないので、Xilinxの純正の波形のデバッグツールであるILA(Integrated Logic Analyzer)を使って内部の信号を観察する方法を見てみる。

ある程度信号波形を取れてきたので、必要な個所にデバッグ信号を入れて動かない場所を特定してみた。

問題になったのは、Vivadoで論理合成されるかどうかを確認せずにTemporaryで入れてしまった$countones()で論理が消えてしまっていたこと(これはVivadoにちゃんとエラーとして出力してほしい...)。 これを解決してとりあえずIssue Queueの問題は消えたが、まだLSUでメモリアクセスを行うとハングしてしまう。引き続き解析をしていこうと思う。