Docker で riscv-tests をビルドする

(ビルドが長くて) 地味に時間がかかったので、今後時間を溶かさないように書き残す。

手順

Dockerfile で riscv-gnu-toolchain 環境を用意

これはほぼ公式手順を Dockerfile に書き起こすだけで良い。ARCH, ABI などは好みのものに変更する。

FROM ubuntu:24.04

WORKDIR /app

# riscv-gnu-toolchainのリポジトリを取得
RUN apt update && apt install -y git
RUN git clone --recursive https://github.com/riscv/riscv-gnu-toolchain

ENV RISCV=/opt/riscv
ENV ARCH=rv32ima
ENV ABI=ilp32
ENV PATH=$RISCV/bin:$PATH
ENV TOOLCHAIN_CONFIGURE="--prefix=$RISCV --with-arch=$ARCH --with-abi=$ABI --enable-multilib --enable-qemu-system"
ENV DEBIAN_FRONTEND=noninteractive

# 必要なパッケージをインストール
RUN apt install -y \
    autoconf \
    automake \
    autotools-dev \
    curl \
    python3 \
    python3-pip \
    python3-tomli \
    libmpc-dev \
    libmpfr-dev \
    libgmp-dev \
    gawk \
    build-essential \
    bison \
    flex \
    texinfo \
    gperf \
    libtool \
    patchutils \
    bc \
    zlib1g-dev \
    libexpat-dev \
    ninja-build \
    git \
    cmake \
    libglib2.0-dev \
    libslirp-dev

# riscv-gnu-toolchainのインストール
RUN cd riscv-gnu-toolchain && \
    ./configure $TOOLCHAIN_CONFIGURE && \
    make -j$(nproc)

CMD ["bash"]

上記 Dockerfile を使って riscv-tests をビルド

multi-stage build で riscv-tests を行っても良かったが、単にビルドするだけであること、自分が実装した別ソースをビルドすることなどを考え先の Image を利用するだけに留めることにした。

docker compose を用意し、成果物 Volume のマウント並びにビルドのワンライナーを用意する。 実装してある内容は riscv-tests の README 通りだが、今回は rv32 を対象にしているので XLEN を設定していること、ISA テスト用に make 対象を isa に絞っている。

services:
  build-riscv-tests:
    build:
      context: .
    volumes:
      - ./riscv-tests:/app/riscv-tests:rw
    command: >
      bash -c "
      cd /app/riscv-tests && 
      git clone --recursive https://github.com/riscv/riscv-tests && 
      cd riscv-tests && 
      autoconf && 
      ./configure --prefix=$RISCV/target && 
      make XLEN=32 isa
      "

使い方

docker compose run build-riscv-tests

その他

riscv-gnu-toolchain のその他のツールを使いたい

docker compose run build-riscv-tests bash で入った環境であれば、他のツールも使える。

$ docker compose run build-riscv-tests bash
root@460560b02bb5:/app# riscv32-unknown-elf-readelf -e -W riscv-tests/isa/rv32ui-p-addi
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           RISC-V
  Version:                           0x1
  Entry point address:               0x80000000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          9524 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         3
  Size of section headers:           40 (bytes)
  Number of section headers:         7
  Section header string table index: 6

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text.init        PROGBITS        80000000 001000 00047c 00  AX  0   0 64
  [ 2] .tohost           PROGBITS        80001000 002000 000048 00  WA  0   0 64
  [ 3] .riscv.attributes RISCV_ATTRIBUTES 00000000 002048 000063 00      0   0  1
  [ 4] .symtab           SYMTAB          00000000 0020ac 0002b0 10      5  37  4
  [ 5] .strtab           STRTAB          00000000 00235c 000198 00      0   0  1
  [ 6] .shstrtab         STRTAB          00000000 0024f4 000040 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  RISCV_ATTRIBUT 0x002048 0x00000000 0x00000000 0x00063 0x00000 R   0x1
  LOAD           0x001000 0x80000000 0x80000000 0x0047c 0x0047c R E 0x1000
  LOAD           0x002000 0x80001000 0x80001000 0x00048 0x00048 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00     .riscv.attributes
   01     .text.init
   02     .tohost

RV64/32 の選択

  • Dockerfile の ARCHABI を変更する
  • make 時の XLEN を変更する
    • riscv-tests のデフォルトは XLEN=64 を使おうとしているので、rv32 向けの toolchain だと gcc などが見つからずエラーになる

Linker script の修正

riscv-tests/env が更に submodule になっており、ここを修正することで対応できる。 例えば p/link.ld は以下の具合

OUTPUT_ARCH( "riscv" )
ENTRY(_start)

SECTIONS
{
  . = 0x80000000;
  .text.init : { *(.text.init) }
  . = ALIGN(0x1000);
  .tohost : { *(.tohost) }
  . = ALIGN(0x1000);
  .text : { *(.text) }
  . = ALIGN(0x1000);
  .data : { *(.data) }
  .bss : { *(.bss) }
  _end = .;
}

この他にも riscv_test.h にテストの各マクロの定義があるので、動作確認向けに変更することもできる。 例えば Pass/Fail は、Pass の場合

//-----------------------------------------------------------------------
// Pass/Fail Macro
//-----------------------------------------------------------------------

#define RVTEST_PASS                                                     \
        fence;                                                          \
        li TESTNUM, 1;                                                  \
        li a7, 93;                                                      \
        li a0, 0;                                                       \
        ecall

#define TESTNUM gp
#define RVTEST_FAIL                                                     \
        fence;                                                          \
1:      beqz TESTNUM, 1b;                                               \
        sll TESTNUM, TESTNUM, 1;                                        \
        or TESTNUM, TESTNUM, 1;                                         \
        li a7, 93;                                                      \
        addi a0, TESTNUM, 0;                                            \
        ecall

disassemble が見たい

付属ツールで disasm 出力しても良かったが、make 時に一緒に生成されていた。 <elf binary>.dump がそれにあたる。

rv32ui-p-addi.dump

rv32ui-p-addi:     file format elf32-littleriscv


Disassembly of section .text.init:

80000000 <_start>:
80000000:	0500006f          	j	80000050 <reset_vector>

80000004 <trap_vector>:
80000004:	34202f73          	csrr	t5,mcause
80000008:	00800f93          	li	t6,8
8000000c:	03ff0863          	beq	t5,t6,8000003c <write_tohost>

...


800003fc <test_25>:
800003fc:	01900193          	li	gp,25
80000400:	02100093          	li	ra,33
80000404:	03208013          	addi	zero,ra,50
80000408:	00000393          	li	t2,0
8000040c:	00701463          	bne	zero,t2,80000414 <fail>
80000410:	02301063          	bne	zero,gp,80000430 <pass>

80000414 <fail>:
80000414:	0ff0000f          	fence
80000418:	00018063          	beqz	gp,80000418 <fail+0x4>
8000041c:	00119193          	slli	gp,gp,0x1
80000420:	0011e193          	ori	gp,gp,1
80000424:	05d00893          	li	a7,93
80000428:	00018513          	mv	a0,gp
8000042c:	00000073          	ecall

80000430 <pass>:
80000430:	0ff0000f          	fence
80000434:	00100193          	li	gp,1
80000438:	05d00893          	li	a7,93
8000043c:	00000513          	li	a0,0
80000440:	00000073          	ecall
80000444:	c0001073          	unimp
80000448:	0000                	.insn	2, 0x
8000044a:	0000                	.insn	2, 0x
8000044c:	0000                	.insn	2, 0x
8000044e:	0000                	.insn	2, 0x
80000450:	0000                	.insn	2, 0x
80000452:	0000                	.insn	2, 0x
80000454:	0000                	.insn	2, 0x
80000456:	0000                	.insn	2, 0x
80000458:	0000                	.insn	2, 0x
8000045a:	0000                	.insn	2, 0x
8000045c:	0000                	.insn	2, 0x
8000045e:	0000                	.insn	2, 0x
80000460:	0000                	.insn	2, 0x
80000462:	0000                	.insn	2, 0x
80000464:	0000                	.insn	2, 0x
80000466:	0000                	.insn	2, 0x
80000468:	0000                	.insn	2, 0x
8000046a:	0000                	.insn	2, 0x
8000046c:	0000                	.insn	2, 0x
8000046e:	0000                	.insn	2, 0x
80000470:	0000                	.insn	2, 0x
80000472:	0000                	.insn	2, 0x
80000474:	0000                	.insn	2, 0x
80000476:	0000                	.insn	2, 0x
80000478:	0000                	.insn	2, 0x
8000047a:	0000                	.insn	2, 0x

LiteX を Ubuntu 24.04 on WSL2 で使用し、 Demo Applicationを動作させる

LiteX を Windows 環境で使用したく、試していたときの備忘録。以下の通り無事 demo app の動作確認までたどり着けたので書き残す。

movie gif


手順まとめ

時系列順に実行した内容のまとめを先に記載する。細かいトラブルシューティングは後半に記載。

環境構築

基本手順は公式ドキュメントの Quick Start Guideに従い、WSL2 上にインストールした Ubuntu 24.04 で行う。 要点は以下。

  • virtualenv を作成し、Python 仮想環境中で実行する
  • virtualenv 中で user install を実行するとエラーになるため、 --user オプションを使用しない
  • litex の repo ごと取得した状態で litex_setup.py を実行しない
# verilator導入
$ sudo apt install verilator

# litexの取得
$ wget https://raw.githubusercontent.com/enjoy-digital/litex/master/litex_setup.py
$ chmod +x litex_setup.py

# venv導入
$ sudo apt install python3-venv
# 仮想環境作成 + activate
$ python3 -m venv .venv
$ source .venv/bin/activate

# litex_setup.py の実行
$ python3 ./litex_setup.py --init --install --config=full

# RSC-V toolchain の導入 (binutils-riscv* 等が導入されるので管理者権限必要)
$ pip3 install meson ninja
$ sudo ./litex_setup.py --gcc=riscv

実機無しでのテスト

ハマりポイントは特になし。verilator があれば動くはず。

Read more  ↩︎

VRChatで動くボードゲームを作る

掲題の通り、VRChat 上で動作するボードゲームを先日公開した。自分自身の備忘録また同様の制作を行いたく情報を探している人向けの制作記録として機能することを願って作業記録を残すことにする。

ss


作るもの

Knucklebones(ナックルボーン)と呼ばれるボードゲームを作ることにした。本家はCult of the Lamb 作中に登場するゲームであり、今回の制作は非公式ファンアートの位置づけである。

サイコロを振って並べるという単純明快なルールでありながら、駆け引き要素がよくできたゲームである。(高得点を狙うほど、相手から一網打尽にされるリスクが上がっていく) もちろん、Knucklebones だけでなくゲーム自体の完成度もすばらしいのでぜひ遊んでみてほしい。

制作手順

おおよそ以下の手順で進めた。あくまでいち参考として見ていただけるとありがたい。

  1. ゲームシステム試作
  2. モデリング
  3. VCC 配布可能な Unity Project 作成
  4. モデルの Unity Setup
  5. ゲームロジック 実装
  6. 動作確認
  7. サンプルワールド作成
  8. 配布準備
Read more  ↩︎

Blog を作る

何度目かはわからないがまだ懲りずにテックブログを作った。 今年に入ってネット隠居やめつつあることや、技術以外の微妙なものの書き置き場所としては自分の置き場が欲しい背景がある...と、 新型コロナウイルス感染症になっている間にぐるぐる考えていて、ちょうどいま病み上がりの今机に座る練習がてら作ってみた。 まだ結構倦怠感があるのとおそらく後遺症ぽいがやたら疲れる。弊はリモートではないのでもう一日大事で休んだほうが良いかもしれない。

ここ数年はあまりアウトプットこそしていなかったが、技術私生活ともにまとめておきたい事柄はあるので、気を見てぼちぼち更新していきたい。