Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LiteXとオレオレCPUで作る自作SoC奮闘記

 LiteXとオレオレCPUで作る自作SoC奮闘記

msyksphinz

April 18, 2025
Tweet

More Decks by msyksphinz

Other Decks in Technology

Transcript

  1. 自作CPUの動作環境 としての LiteX • 趣味でアウト・オブ・オーダCPUを作った。 • FPGAに焼き込んで動かすために、SoCプラットフォームのLiteX を使用した • LiteXについて調査・試行したことをFPGAマガジンに執筆した

    • オープンソースのLiteXを使ってSoCを組み上げ、FPGAで動かし た。 • 2024年4月号「SoC構築フレームワークLiteX」 • 2025年4月号「LiteXでCPUと周辺回路を組み込む」 • 今回はそれに関して、もうちょっと砕けた表現で 話をしたいと思います。 2
  2. LiteXがサポートするCPUとFPGA CPU • RISC-V • blackparrot • cv32e40p • cv32e41p

    • cva5 • cva6 • fazyrv • femtorv • firev • gowin_ae350 • ibex • kianv • minerva • naxriscv • neorv32 • openc906 FPGA • Xilinx • ac701 • alveo_u200 • alveo_u250 • alveo_u280 • kc705 • kcu105 • kv260 • vc707 • vcu118 • vcu128 • zc706 • zcu102 • zcu104 • zcu106 • zcu216 • zybo_z7 • RISC-V • picorv32 • rocket • sentinel • serv • urv • vexiiriscv • vexriscv • vexriscv_smp • ARM • cortex_m1 • cortex_m3 • eos_s3 • gowin_emcu • zynq7000 • Digilent • arty • arty_s7 • arty_z7 • atlys • basys3 • cmod_a7 • genesys2 • netfpga_su me • nexys4 • nexys4ddr • nexys_video • pynq_z1 • zedboard • terasic • lattice • sipeed • antmicro • その他多数 6
  3. LiteXが提供するSoCの基本構成 • 基本はCPUと周辺I/O • どういう周辺I/Oを載せるかは使う FPGAによる CPU0 CPU1 L2 Cache

    UART SPI DDR Controller Flash Controller Timer User I/O DDR Memory SPI Flash この辺の組み合わせは 使用するFPGAによる https://github.com/enjoy-digital/litex?tab=readme-ov-file 7
  4. シミュレーション環境の生成 $ litex_sim –cpu-type=vexriscv CPUとしてVexRiscvを使いSoCを構成する場合 • 中で行われること • VexRiscvが組み込まれたSoC RTLファイルの生成

    • ファームウェアの生成 • ファームウェアのビルド • Verilatorを用いたSoC RTLのコンパイル・シミュレーションバイナリ作成 • シミュレーション実行 8
  5. 実行後の様子 • これなに? • 最初これが何者なのか良く分からなかった • なんか超シンプルなBIOSみたいなもの • CPU上で(コンパイルした)ブートローダが) 動き、このメッセージを表示する

    • (逆に言えば)このメッセージが出れば、 CPUは正しく動いている言える [ethernet] loaded (0x563eb1924ef0) [gmii_ethernet] loaded (0x563eb1924ef0) [serial2console] loaded (0x563eb1924ef0) [serial2tcp] loaded (0x563eb1924ef0) [spdeeprom] loaded (addr = 0x0) [xgmii_ethernet] loaded (0x563eb1924ef0) [clocker] loaded [jtagremote] loaded (0x563eb1924ef0) [clocker] sys_clk: freq_hz=1000000, phase_deg=0 __ _ __ _ __ / / (_) /____ | |/_/ / /__/ / __/ -_)> < /____/_/¥__/¥__/_/|_| Build your hardware, easily! (c) Copyright 2012-2024 Enjoy-Digital (c) Copyright 2007-2015 M-Labs BIOS built on Apr 13 2025 15:38:08 BIOS CRC passed (0cc73860) LiteX git sha1: 4e4e44f49 --=============== SoC ==================-- CPU: VexRiscv @ 1MHz BUS: wishbone 32-bit @ 4GiB CSR: 32-bit data ROM: 128.0KiB SRAM: 8.0KiB --============== Boot ==================-- Booting from serial... Press Q or ESC to abort boot completely. sL5DdSMmkekro Timeout No boot medium found --============= Console ================-- litex> 9
  6. FPGAビルド環境の生成 $ python3 –m litex_boards.targets.digilent_arty ¥ --output-dir build_fpga --cpu-type=vexriscv CPUとしてVexRiscvを使いDigilent

    Nexys Video 向けにVivadoを走らせ、bitファイルを作成 • 中で行われること • VexRiscvが組み込まれたSoC RTLファイルの生成 • ファームウェアの生成 • ファームウェアのビルド • RTLをVivadoで合成してbitファイルを作成 10
  7. FPGAで動かす様子 • シリアルコンソールからアクセスする。 • キーボードからインタラクティブな 動作が可能 • つまりPLICとかのサポートが必要 • 地獄

    • donutコマンド:ドーナツを出す。 • 開発サーバが一時的にアクセスできなくて、過去の ブログの写真ですみません。 11
  8. 違和感を覚えた方、するどい • 実はRTLシミュレーション用とFPGA合成用に生成されたVerilog ファイルは全然違う • RTLシミュレーション用: ./build/sim/gateware/sim.v • FPGA合成用: ./build_fpga/gateware/sim.v

    • RTLシミュレーション用は、FPGAに依存しない汎用デザイン • UARTモデルも可能な限り簡単化 • たぶん動作の高速化のため • I/Oピンも最小限に抑えられている • litex_simで動いたからってFPGAで動くとは限らない! • これに気が付かず、のちのち地獄を見る羽目に… 12
  9. 自作RISC-V CPUの概要 • 趣味でアウト・オブ・オーダの自作CPUを作った • ISA RISC-V RV32 / RV64サポート

    • RV32IMAFDCB / RV64IMAFDCB / Zicond • FDはオプションで取り外し可 • https://github.com/msyksphinz-self/scariv_zero • SCARIV : Scalable RISC-V Processor • 読み物として:./docs/ 以下に実装時に考えた いろんなことが書いてある。 • 性能的にはあんまり良いものではないので 中身をあんまりじっくり見ないでください(笑) 15
  10. 自作CPUの構成概要 • 割と一般的なアウト・オブ・オー ダ構成(だと思う) • かなりコンフィギャラブル • ディスパッチ幅、キューの大きさ、パ イプライン数など •

    TLBも入っているので、ユーザモー ド付のOSとかも動く(はず) • Linuxのブートとかも試した (未完) • インタフェース • 命令フェッチ用I/F • データ・アクセス用I/F • PTW (MMUで使用する) 用I/F • スヌープ操作受付用 I/F FPUブロック メモリ・ アクセス ブロック 整数ブロック リネーム・ディスパッチ フロントエンド 命令キャッシュ 命令フェッチ・ ユニット 命令フェッチ・ バッファ 命令切り出し 整数レジスタリネーム 浮動小数点レジスタリネーム ALU命令 キュー ALU命令 キュー FPU命令 キュー LSU命令キュー 整数物理レジスタファイル FP物理レジスタ ファイル ロード キュー ストア キュー マージ・バッ ファ データ キャッシュ DTLB ITLB リオーダ・バッファ 分岐予測 PTW ALU ALU FPU Snoop Unit 命令キャッシュI/F PTW I/F Snoop I/F データキャッシュ I/F 16
  11. ここまでのまとめ + 余談 • LiteXへの組み込み対象として、自作アウト・オブ・オーダCPU を使用した • 空いた時間でコツコツ作っていたもの • 作りとしてはかなり甘いよ

    • 性能があまり出ないよ • 直したいところ • フロントエンド:分岐予測の作りこみが甘い • マルチコア化とかしたい 18
  12. RTLシミュレーションでの 動作確認 $ litex_sim –cpu-type myooo –output-dir sim_myooo __ _

    __ _ __ / / (_) /____ | |/_/ / /__/ / __/ -_)> < /____/_/¥__/¥__/_/|_| Build your hardware, easily! (c) Copyright 2012-2024 Enjoy-Digital (c) Copyright 2007-2015 M-Labs BIOS built on Dec 2 2024 01:07:41 BIOS CRC passed (d7b03e99) LiteX git sha1: 30aeaf544 --=============== SoC ==================-- CPU: MyOOO 64-bit @ 1MHz BUS: wishbone 32-bit @ 4GiB CSR: 32-bit data ROM: 128.0KiB SRAM: 8.0KiB --============== Boot ==================-- Booting from serial... Press Q or ESC to abort boot completely. sL5DdSMmkekro Timeout No boot medium found --============= Console ================-- litex> help LiteX BIOS, available commands: flush_cpu_dcache - Flush CPU data cache crc - Compute CRC32 of a part of the address space ident - Identifier of the system help - Print this help serialboot - Boot from Serial (SFL) reboot - Reboot boot - Boot from Memory mem_cmp - Compare memory content mem_speed - Test memory speed mem_test - Test memory access mem_copy - Copy address space mem_write - Write address space mem_read - Read address space mem_list - List available memory regions 22
  13. LiteX SoC ってまあ、動くわけないよね • 最初はだいたい何も表示されない • どうすんねん • 何が起きているのか確認したい •

    LiteX環境だと、CPU単体の検証環境が使えない • 独自にLiteX内にトレース出力ファイル出力機構を挿入する必要がある DUT CPU Monitor Spike DPI Env Spike Compare env CPU Trace Dumper 23
  14. ひたすらトレースを吐いて、 おかしいところを解析する • 所望の動作になっているかを確認 • ファームウェアのプログラム • 逆アセンブリ結果 • RTLシミュレーション・トレース結果

    • RISC-V PLICの仕様の完全な理解 • 必要となるもの • ファームウェアの完全な理解 • 特に割り込み挿入時のルーチンの挙動 • 根気 • これに関しては、いろいろ試行錯誤するより まずはソフトウェアの完全な理解が必要だと思う • かなり Run より論 398152000000 ( 9, 1) PC=0x0000001d46: 000060e2 c.ldsp ra, 24(sp) GPR[ 1](20) <= 0000000000000000 398152000000 ( 9, 2) PC=0x0000001d48: 00006125 c.addi16sp sp, 96 GPR[ 2](01) <= 0000000020001f40 398153000000 (10, 1) PC=0x0000001d4a: 00008082 ret GPR[ 0](00) <= 0000000000000000 398166000000 (11, 1) PC=0x0000000000: 0000a8b5 c.j pc + 124 GPR[ 0](00) <= 0000000000000000 398223000000 (12, 1) PC=0x000000007c: 20002117 auipc sp, 0x20002 GPR[ 2](0b) <= 000000002000207c 398224000000 (13, 1) PC=0x0000000080: f8410113 addi sp, sp, -124 GPR[ 2](14) <= 0000000020002000 398229000000 (14, 1) PC=0x0000000084: 20000297 auipc t0, 0x20000 GPR[ 5](25) <= 0000000020000084 398229000000 (14, 2) PC=0x0000000088: 4602be23 sd zero, 1148(t0) 398230000000 (15, 1) PC=0x000000008c: 00000297 auipc t0, 0x0 GPR[ 5](15) <= 000000000000008c 24
  15. LiteXの提供するファームウェア • 割り込み処理周りの理解が必要 • PLICからの割り込み挿入時の動作 • つまりキーボードからの入力があった場合 void isr(void) {

    unsigned int claim; /* Claim and handle pending interrupts. */ while ((claim = *((unsigned int *)PLIC_CLAIM))) { unsigned int irq = claim - PLIC_EXT_IRQ_BASE; if (irq < CONFIG_CPU_INTERRUPTS && irq_table[irq].isr) { irq_table[irq].isr(); litex/litex/soc/software/libbase/isr.c void uart_isr(void) { unsigned int stat, rx_produce_next; stat = uart_ev_pending_read(); if(stat & UART_EV_RX) { while(!uart_rxempty_read()) { rx_produce_next = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX; if(rx_produce_next != rx_consume) { rx_buf[rx_produce] = uart_rxtx_read(); rx_produce = rx_produce_next; } uart_ev_pending_write(UART_EV_RX); #if defined(__cva6__) asm volatile("fence¥n"); #endif } } if(stat & UART_EV_TX) { uart_ev_pending_write(UART_EV_TX); while((tx_consume != tx_produce) && !uart_txfull_read()) { uart_rxtx_write(tx_buf[tx_consume]); tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX; } } } litex/litex/soc/software/libbase/isr.c UARTの読みみ PLICの状態読み込み (Pending Bit) UARTへの書き込み 25
  16. バグ・バグ・バグ • 内部バスプロトコルをAXIに置き換えるユニットのバグ • 通常シミュレーション時はAXIサブシステムをスキップしていた • ファームウェアの一部に不具合 • PLICから割り込みを受け付けて割り込みシーケンスを処理する前に MSTATUS.MIEを落としていない

    • LiteXのAXIバス実装自体に不具合? • LiteXのプロトコルは通常Wishboneが使われる • CPUのAXIバスをWishboneに変換しているっぽい • AXIを直接つっ込むと、どこかでAxIDが消える • ちょっと真剣に取り組まないと解析できない (時間切れ) • だれか解析して… • 結局内部ではWishboneを使っている • アウトスタンディングが確保できず、アウト・オブ・オーダが全く活用できない 26
  17. FPGAビルド・動作確認 • 通常は 100MHz 駆動だが、自作CPUのチューニング不足により 40MHz 動作 • かなり安全方向に振って動作確認をする •

    行われること • RTL生成 • ファームウェア生成・ビルド • Vivadoの起動・論理合成・bitファイル作成 • ↑で「RTL生成」といったな? • やはりRTLシミュレーション用とFPGA実行用で異なるRTLが生成される • やはり地獄を見る $ python3 -m litex_boards.targets.digilent_nexys_video ¥ --cpu-type=myooo --build --output-dir fpga_myooo ¥ --sys-clk-freq 40000000 27
  18. FPGAでの動作確認 • FPGA向けのデザインはSDRAMコントローラ とかついてる • ファームウェアも微妙に異なる • また挙動を一から確認か… • まあ、動くわけないよね

    (その2) • → の部分までいくのに一苦労 • この部分で止まったり、ランダムな場所で止まっ たりと何が起きているのか全く分からん 28
  19. 結局ILA頼み • Integrated Logic Analyzer • (FPGAのロジアナ) • CPUの命令コミット周り •

    バス周辺 • とにかく止まっていそうな部分にひたすらILAを挿入し、問題を絞り込む 29
  20. LiteX の論理合成フローにILAの 挿入プロセスはない • 上記のLiteXのFPGA合成フローでは、ILA を挿入できない • LiteX にも ILA

    に近い機能 (LiteScope) があるが、 UART経由では遅すぎる • 結論:LiteXのVivado論理合成スクリプト を全部パクリ、 独自のVivado論理合成フローを構築 • スクリプト内に ILA 構築コマンドをひたすら ぶち込んでいく # ILA create_debug_core u_ila_0 ila set_property C_DATA_DEPTH 1024 [get_debug_cores u_ila_0] set_property C_TRIGIN_EN false [get_debug_cores u_ila_0] set_property C_TRIGOUT_EN false [get_debug_cores u_ila_0] set_property C_ADV_TRIGGER false [get_debug_cores u_ila_0] set_property C_INPUT_PIPE_STAGES 0 [get_debug_cores u_ila_0] set_property C_EN_STRG_QUAL false [get_debug_cores u_ila_0] set_property ALL_PROBE_SAME_MU true [get_debug_cores u_ila_0] set_property ALL_PROBE_SAME_MU_CNT 1 [get_debug_cores u_ila_0] connect_debug_port u_ila_0/clk [get_nets [list sys_clk]] set_property port_width 1 [get_debug_ports u_ila_0/probe0] set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe0] connect_debug_port u_ila_0/probe0 [get_nets main_basesoc_dbus_ack] set debug_nets [lsort -dictionary [get_nets -regexp main_basesoc_dbus_cyc.*]] set new_port [create_debug_port u_ila_0 probe] set_property port_width [llength $debug_nets] $new_port set_property PROBE_TYPE DATA_AND_TRIGGER $new_port connect_debug_port $new_port $debug_nets この辺の怪しい論理を ひたすらILAにぶち込む 30
  21. LiteX FPGA向けRTLをそのままRTLシミュレーション • FPGA向けに生成したデザインを、結局手元でRTLシミュレーション • これも、 litex_sim に依存しない環境を構築 • FPGA向けのデザイン・ファームウェアにはSDRAMの初期化とかが含まれる

    • 全部RTLシミュレーションする必要がある → めっちゃ時間がかかる • あとは根気の問題 • 途中でキーボード挿入向けの割り込みとかをランダムに入れてみる • とにかく問題を再現して解析可能な広域波形ファイルを取得することが目的 FPGA specialized SoC design Vivado scripts RTL simulation environment FPGA specialized SoC design Verilator environment 31