Dev ContainersでVerilog開発環境を作ってみた


## はじめに

最近、趣味でCPUの技術書を読んでおり、その中で論理回路に（大学生の時ぶりに）出会いました。
せっかくなのでハードウェア記述言語（HDL）で論理回路を実装しようとした時、ふと「Dev Containersを使ってHDLの開発環境も作れるのでは？」と思ったので作ってみました。
今回は、その手順を記事としてまとめたものです。
Verilog環境構築したい方はもちろんですが、コンテナー上で起動した波形ビューアーをローカルで見られるようにX Window Systemを設定する必要があり、Dev Containers × X Window Systemの活用例が気になる方にも参考になれば幸いです。

## 対象者

- MacユーザーでVerilogの開発環境を簡単に構築したい方
- Verilogは使うかわからないけど、Dev ContainersでX Window Systemを使用する方法が気になる方

:::note warn
実行環境の詳細は以下の通りです。

- macOS 14.3
- VS Code 1.87.2
- Dev Containers v0.353.0
:::

## 結論

先に環境構築に必要な手順を以下にまとめます。結構たくさんのステップがありますね。

1. ホスト（Mac）上にX Window Systemのホスト設定を行う
1. Dev Containersを使用可能にする（Docker環境を構築する）
1. Verilog開発用のコンテナーを作成する
1. 開発環境が問題ないか（コンパイルやシミュレーションが行えるか）の確認

## 構築手順

### ホスト（macBook）上の設定

1. [Xquartz](https://www.xquartz.org/index.html)をインストール  

    Xquartzとは、mac上でX Window System[^1]を動作させるためのソフトウェアです。具体的には、コンテナー上で起動したgtkwave（波形ビューアー）をmac上で表示するために必要となります。

    [^1]: X Window Systemは、主にUNIX系OSで使用される、GUIを提供するためのシステムです。リモートのUNIXサーバー上で動作するソフトウェアを、クライアントのX Window Systemを通じて操作することが可能です。今回は、サーバーがコンテナーであり、クライアントがmacBookとなります。

    ```bash
    brew install --cask xquartz
    ```

2. Xquartzの設定を変更

    1. 以下のコマンドを実行して、Xquartzアプリを開きます。

        ```bash
        open -a Xquartz
        ```

    2. `Xquartz` -> `Settings` -> `Security`タブを開き、`Allow connections from network clients`にチェックを入れます。
        <img width="500" alt="xquarz_setting" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/89057c6d-50b4-f229-7b00-9ae8d319697f.png"/>

    3. 一度ログアウトして再ログイン  
       左上のAppleマークをクリックして、`ログアウト`を選択してログアウトし再度ログインします

    4. Display環境変数が設定されるか確認  
       以下のコマンドを実行して、Display環境変数を表示してください。

        ```bash
        echo $DISPLAY 
        # /private/tmp/com.apple.launchd.xxxxxxxxxx/org.xquartz:0 のような文字列が表示されたらOK
        ```

3. xhostを設定  
   以下のコマンドを実行して、xhostを設定します。

    ```bash
    xhost + localhost
    # xhostコマンドが見つからない場合は、以下を実行してください
    /asr/X11/bin/xhost + localhost
    ```

### Dev Containersの設定

まずDev Containersについて簡単に説明します。

- 開発環境をコンテナー上に構築できるVS Codeの拡張機能
  - ローカルの環境に影響を与えず開発環境を構築できる
- Dockerと異なり、VS Codeの拡張機能や設定ファイルもコンテナーに紐づけることができるため、複数人での開発する際に非常に便利

それではDev Containersの設定方法を見ていきましょう。

1. Dev Containersのインストール
VS Codeの拡張機能から[Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)を検索してインストールします。

2. Docker環境を構築
Dev Containersを使用するには、ローカルでDocker環境を構築する必要があります。
macOSでDocker環境を構築するには、[Docker Desktop](https://www.docker.com/ja-jp/products/docker-desktop/)をインストールする方法が簡単だと思いますので、[こちら](https://matsuand.github.io/docs.docker.jp.onthefly/desktop/mac/install/)を参照してください。[^2]

3. コンテナーを起動できるか確認
    1. 左下のボタンをクリック
        <img width="400" alt="dev_container_button" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/7daadc91-1c15-691e-8305-fb74f4a6e780.png"/>
    2. New Dev Containerを選択
        <img width="500" alt="new_dev_container" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/8f606da9-cfab-4966-937e-0acc94abc346.png"/>
    3. 好きなコンテナーを選択して起動する
        <img width="500" alt="select_container" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/9abf250a-3da6-c67a-ac86-994e60bbb908.png"/>  
        これでコンテナーが起動できれば、Dev Containersの設定は完了です。

[^2]: Docker Desktopは、大規模エンタープライズ（従業員250名以上、または年間収益1千万USドル以上）向けの商用利用に対し、有償サブスクリプションが必要となっていますので注意してください。またDocker Desktopを用いずにDocker環境を構築する方法としては、Rancher Desktopやcolimaなどを使用する方法あります。

### Verilog開発用のワークスペースを作成

1. ワークスペース用ディレクトリの作成
    今回は`verilog_workspace`というディレクトリを作成します。

    ```bash
    mkdir verilog_workspace
    ```

2. `devcontainer.json`の作成
    1. 1で作成したディレクトリをVS Codeで開く
    2. コマンドパレット（ショートカットは、`Cmd + Shift + P`）を開き、`Dev Containers: Add Dev Container Configuration Files...`を入力して選択
        <img  width="500"  alt="command_pallet" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/cf4f1d80-a65b-ec26-8405-8a1a83d94ccd.png">
    3. `Add configuration to user data folder`を選択
        <img width="500" alt="add_configuration" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/a5376b42-a269-8c6c-bdaf-ce8d67b9a0b6.png"/>
    4. `Ubuntu`、`jammy`を選択
        <img width="500" alt="select_ubuntu" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/9abf250a-3da6-c67a-ac86-994e60bbb908.png"/>
        <img width="500" alt="select_jammy" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/2b7ec651-3869-0e1a-d386-ba47ec196bcf.png"/>
    5. Select Featuresは何も選択せずOKをクリック
        <img width="500" alt="select_features" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/c0a75d20-5dbc-bea5-8813-2235275eb3b0.png"/>

3. `devcontainer.json`に以下のように変更

    ```json
    {
        "name": "Ubuntu",
        "image": "mcr.microsoft.com/devcontainers/base:jammy",
        "customizations": {
            "vscode": {
                "extensions": [
                    "leafvmaple.verilog",
                ],
            }
        },
        "runArgs": [
            "-e",
            "DISPLAY=host.docker.internal:0"
        ],
        "postCreateCommand": "sudo apt update && sudo apt install -y iverilog gtkwave xserver-xorg"
    }
    ```

    追加した設定の詳細は以下のとおりです。

    - `customizations`
      - ワークスペース上でのVS Codeの設定を定義
      - 今回は、Verilogのシンタックスハイライトを行うVS Codeの拡張機能である`leafvmaple.verilog`をインストールしています。
    - `runArgs`
      - コンテナー内でX Window System（後述するgtkwaveで必要）を使用するために、DISPLAY環境変数を設定しています。
    - `postCreateCommand`
      - コンテナー作成後に実行するコマンドを指定
      - 今回は、iverilog（Verilogのコンパイラー）、gtkwave（波形ビューアー）、xserver-xorg（X Window System）をインストールしています。

4. コンテナー起動
    devcontainer.jsonを保存した後、VS Codeの右下にある`Reopen in Container`を選択してコンテナーを起動します。

    <img width="500" alt="reopen_in_container" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/a5f594ae-6685-9098-f9d8-7a755c888dc7.png"/>

### Verilogのコンパイルやシミュレーションの確認

それではVerilogのコンパイルやシミュレーションを行ってみましょう。
今回は、以下の記事を参考にAND回路を実装＆シミュレーションしようと思います。

<!-- markdownlint-disable MD034 -->

https://qiita.com/aurueps/items/72444c9b44a6940825f1

<!-- markdownlint-enable MD034 -->

1. モジュールファイルとテストベンチファイルの作成
以下のモジュールファイル（`and.v`）とテストベンチファイル（`and_test.v`）を作成する

    ```verilog:and.v
    module AND(
            input wire in0,
            input wire in1,
            output wire out0
            );
            assign out0 = in0 & in1;
    endmodule
    ```

    ```verilog:and_test.v
    module ANDTEST;

    reg a, b;
    wire c;

    AND and_instance(a, b, c); 

    initial begin
            $dumpfile("and_test.vcd");
            $dumpvars(1, ANDTEST);

            a = 0; b = 0;
            #10 a = 1;
            #10 a = 0; b = 1;
            #10 a = 1;
            #10 a = 0; b = 0;
            #10 $finish;
    end

    endmodule
    ```

2. コンパイルおよびシミュレーションの実行

    ```bash
    # コンパイル
    iverilog -o andtest -s ANDTEST and_test.v and.v
    # vcdファイルの作成
    vvp andtest.out
    # シミュレーターの起動
    twinwave + and_test.vcd
    ```

    シミュレーターの起動まで完了すると、`gtkwave`が起動し、Xquartz上で波形を確認できるようになります

    <img width="500" alt="gtkwave" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646568/1468fc79-4a1d-1739-9567-0c126f4096f4.png"/>

### （補足）シミューレーターの起動がうまくいかない時

- `Error: Can't open display: host.docker.internal:0`が表示される場合
  - Xquartzが起動しているか確認する
  - Xquartzの設定がうまく行えているか確認する

- `Authorization required, but no authorization protocol specified`が表示される場合
  - `xhost + localhost`を再実行する  
    Xquartzを終了すると再度`xhost + localhost`を実行する必要があるので注意

## おわりに

はじめてDev Containersを使用した方は少し苦労したかもしれませんが、慣れると環境構築が非常に楽になると思います。もし途中でつまずいても、また最初からコンテナーを作り直せるのはDev Containersの良いところですね。
それでは良いVerilogライフを！

## 参考記事

- <https://qiita.com/ikedaHi/items/a29a5e238411b1d8bfa0>
- <https://gist.github.com/cschiewek/246a244ba23da8b9f0e7b11a68bf3285>
- <https://qiita.com/loftkun/items/37340745f211ea5d7ece>
- <https://gokids.hatenablog.com/entry/2018/11/14/190000>
- <https://qiita.com/aurueps/items/72444c9b44a6940825f1>