RISC-V QEMU で動作するベアメタルプログラム

RISC-V量子拡張は, 「RiscV.RV32IU」として @k_yamaz 蛙 が提案しています.
(詳しくは, 技術ブログ Qiita に投稿した RISC-Vの量子計算拡張 をご参照ください. )
思いつきなどをメモしていきます.

VSCode でビルドしたプログラムの動作がうまく行かないままですので, 自作でベアメタルプログラムのサンプルを作成します.

簡単なテストコードとして, 次の main.c を作成します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define UART0DR (volatile unsigned char *) 0x10000000
#define PRINT_UART0(x) print_uart(UART0DR, x)

void print_uart(volatile unsigned char* base_addr, const char *s) {
while(*s != '\0') {
*UART0DR = (unsigned char)(*s);
s++;
}
}

int main() {
const char* msg = "Hello world!\n";
PRINT_UART0(msg);
return 0;
}

ライブラリが使えないので, UART0 のアドレスにメッセージ ( msg )のキャラクタコードを書き込むプログラムです.

つぎに, 簡易的なブートローダー startup.S を作成します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.align 6

.equ UART_BASE, 0x10000000
.equ REG_RBR, 0
.equ REG_TBR, 0
.equ REG_IIR, 2
.equ IIR_TX_RDY, 2
.equ IIR_RX_RDY, 4

.section .text
.globl _start
.globl stack_top

_start:
la sp, stack_top
call main

loop_here: j loop_here

次のリンカーに渡すセクション等を定義したスクリプト ( link.ld ) を使って, この2つのプログラムをコンパイルします.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
SECTIONS
{
/* text: test code section */
. = 0x80000000;
.text : { *(.text) }
/* data: Initialized data segment */
.data : { *(.data) }
.rodata : { *(.rodata) }
.sdata : { *(.sdata) }
.debug : { *(.debug) }
. += 0x8000;
stack_top = .;

/* End of uninitalized data segement */
_end = .;
}

(コンパイルの実行)

1
riscv32-unknown-elf-gcc -T link.ld startup.S main.c -o hello -mabi=ilp32 -fPIC -nostdlib -nostartfiles

(QEMUでベアメタルプログラムとして実行)

1
qemu-system-riscv32 -nographic -machine virt -kernel hello

(出力される画面)

1
Hello world!

Ctrl-A x で QEMU は終了します.

RISC-V の開発環境

RISC-V量子拡張は, 「RiscV.RV32IU」として @k_yamaz 蛙 が提案しています.
(詳しくは, 技術ブログ Qiita に投稿した RISC-Vの量子計算拡張 をご参照ください. )
思いつきなどをメモしていきます.

RISC-V の開発環境を整えています. Visual Studio Code で開発環境を整えます.

  • VSCode を起動

  • “PlatformIO IDE” の Extension をインストール(Extensionsタブをクリックして, 検索欄から “PlatformIO” を検索)
    ※インストール時の出力 Window を閉じてしまわないように注意.

  • コマンドパレット(Ctrl + Shift + P or 左下の設定アイコン => Command Palette)を開き, “PlatformIO”と検索

  • “PlatformIO : Home”を選択し, 起動

  • New Projectを選択し, Name, Board, Framework を入力

    • Name : プロジェクトの名前 (”risc-q”と入力)
    • Board : ボードの種類. (”HiFive1(SiFive)”を選択)
    • Framework : Boardに合わせた選択肢. (”Freedom E SDK”を選択)

しばらく待つと利用可能になります.

簡単なテストコードとして, 次の src/test.c を作成します.

1
2
3
4
5
6
#include <stdio.h>

int main(int argc, char **argv) {
printf("Hello RISCV\n");
return 0;
}

コマンドパレット(ビルドは “PlatformIO : Build”), または下部の青いバーにあるアイコンで, ビルドを行います.
.pioenvs/hifive1/firmware.elf に ELF 形式のファイルが作られます. コマンドプロンプトから, 次のようなコマンドで
firmware.elf を読み込むと実行できるはずでした. (がうまくいきません. 動かない理由を調査して次回以降に報告します. )

1
qemu-system-riscv32 -nographic -machine sifive_e -kernel firmware.elf

(出力される画面)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
qemu: hardware error: sifive_prci_read: read: addr=0xc

CPU #0:
pc 20401d82
mhartid 00000000
mstatus 00000000
mip 00000000
mie 00000000
mideleg 00000000
medeleg 00000000
mtvec 204001dc
mepc 00000000
mcause 00000000
zero 00000000 ra 20401b6c sp 80000c30 gp 80000f90
tp 00000000 t0 20402ba0 t1 20402020 t2 80000878
s0 80000000 s1 20401d82 a0 80000874 a1 1000800c
a2 ffffffff a3 204022b8 a4 00010000 a5 10008000
a6 7fffffff a7 00000000 s2 20402b90 s3 00000000
s4 00000000 s5 00000000 s6 00000000 s7 00000000
s8 00000000 s9 00000000 s10 00000000 s11 00000000
t3 00000000 t4 00000000 t5 00000000 t6 00000000
ft0 0000000000000000 ft1 0000000000000000 ft2 0000000000000000 ft3 0000000000000000
ft4 0000000000000000 ft5 0000000000000000 ft6 0000000000000000 ft7 0000000000000000
fs0 0000000000000000 fs1 0000000000000000 fa0 0000000000000000 fa1 0000000000000000
fa2 0000000000000000 fa3 0000000000000000 fa4 0000000000000000 fa5 0000000000000000
fa6 0000000000000000 fa7 0000000000000000 fs2 0000000000000000 fs3 0000000000000000
fs4 0000000000000000 fs5 0000000000000000 fs6 0000000000000000 fs7 0000000000000000
fs8 0000000000000000 fs9 0000000000000000 fs10 0000000000000000 fs11 0000000000000000
ft8 0000000000000000 ft9 0000000000000000 ft10 0000000000000000 ft11 0000000000000000
Abort trap: 6

RISC-V 量子拡張 (2. カスタム拡張を考える)

RISC-V量子拡張は, 「RiscV.RV32IU」として @k_yamaz 蛙 が提案しています.
(詳しくは, 技術ブログ Qiita に投稿した RISC-Vの量子計算拡張 をご参照ください. )
思いつきなどをメモしていきます.

RISC-Vの 量子計算拡張を考えています.
RISC-Vには custom0 〜 custom3 までの 4つの拡張命令が予め定義されています.
opcode では, custom0 = 0xb, custom1 = 0x2b, custom2 = 0x5b, custom3 = 0x7b が割り当てられています.
量子拡張では, 「1量子ビットのユニタリ演算」「2量子ビットのユニタリ演算」「量子ビットの射影測定」「量子ビットの初期化」「レジスタ間の移動」を追加することを考慮したいです.

拡張命令の検討の前に, レジスタについて考える必要があります. 通常のRV32Iの仕様では 32bit レジスタの個数は32個の x0 から x31 と定義してあり,
それぞれの番号のなかには特殊な役割をもっているレジスタもあります. 例えば, x0 は zero を表すレジスタと決まっている等.
そこで, 同じく量子レジスタも q0 から q32 の32個ある仕様として進めます. また, q0 は qzero を表すレジスタとし, ほかにも今後必要に応じて, 量子レジスタの役割も決めていきます.
当面, 量子レジスタは, 命令が呼ばれる前後で量子状態が保持される “保存レジスタ” としておきます.

さてここで, 拡張命令セットに戻ると, 「量子ビットの初期化」「レジスタ間の移動」は古典命令セットを流用できそうです. (別で検討します. )
つまり, 「1量子ビットのユニタリ演算」「2量子ビットのユニタリ演算」「量子ビットの射影測定」を拡張命令セットの opcode に割り当てることを想定します.

custom1 := 1量子ビット・ユニタリ演算
custom2 := 2量子ビット・ユニタリ演算
custom3 := 量子ビットの射影測定

とおきます. (custom0 は今後の検討で必要になるかもしれません. 今は定義することを考えないで空けておきます. )
この custom1/2/3 の opecode の定義は, toolchain の riscv-binutils/include/opcode/riscv-opc.h にあります.
なお, 同一の情報が riscv-gdb/include/opcode/riscv-opc.h, riscv-qemu/include/disas/riscv-opc.h にもあります. 修正するときには留意しましょう.
この riscv-opc.h には, custom1/2/3 の引数のタイプに応じて, customX_rs1, customX_rs1_rs2, customX_rd, customX_rd_rs1, customX_rd_rs1_rs2 が利用可能となっています.

詳細の検討は更に重ねる必要がありますが, 1量子ビット・ユニタリ演算は custom1_rs1, 2量子ビット・ユニタリ演算は custom2_rs1_rs2, 量子ビット射影測定は custom3_rs1_rs2 (rs2は古典レジスタ)で表せると仮定します.

RISC-V toolchain(開発環境を整える)

RISC-V量子拡張のバイトコードを LLVM バックエンドから出力できることを目指していますが, LLVM 単体のコンパイルには非常にリッチな計算リソースが必要になります.

量子拡張のバイトコードを検討するにはとても試行錯誤することが予想されます. そこで, LLVM を改造していくことは少し先送りして, riscv-gnu-toolchain を使って色々と試せるようにします.
RISC-Vの32ビット対応を拡張することを考えていますので, 次のように arch や abi を限定してビルド環境を整えます.

1
2
3
4
5
6
$ git clone https://github.com/riscv/riscv-gnu-toolchain.git
$ cd riscv-gnu-toolchain
$ mkdir build
$ ../configure --prefix=/opt/riscv --with-arch=rv32gc --with-abi=ilp32d
$ make
$ sudo make install

LLVM Frontend は, OpenMP をお手本に #pragma による拡張を目指すため, toolchain ではうまく行かない想定ですが, バイトコードの検討はこの環境で試行錯誤していきます.

QEMU の RISC-V(1. RISC-V量子拡張の対応方針)

RISC-V量子拡張は, 「RiscV.RV32IU」として @k_yamaz 蛙 が提案しています.
(詳しくは, 技術ブログ Qiita に投稿した RISC-Vの量子計算拡張 をご参照ください. )
思いつきなどをメモしていきます.

RISC-V量子拡張を定義して, その QPU をエミュレートするには, QEMU で「RISC-V ISA U Extension (RISC-V 量子拡張) 」を動作させることを考えます.
まず, QEMU をコンパイルする環境を構築します.

以下により ${RISCV}/bin に qemu-system-riscv32 がインストールされる開発環境が準備できます.

1
2
3
4
5
$ git clone https://github.com/qemu/qemu.git
$ cd qemu
$ mkdir build
$ cd build
$ ../configure --target-list=riscv32-softmmu --prefix=${RISCV}

この開発環境で, RISC-V U Extension を追加していきます.
RISC-V の仮想CPUのコードは, target/riscv にあります.

まず手始めに, cpu.h に Extension の定義を追加しましょう.

1
2
3
4
#define RVI RV('I')
#define RVE RV('E') /* E and I are mutually exclusive */
:
#define RVU RV('U')

とある RVI, RVE, … です. 量子拡張はU としましたが, RVU が定義されています. ということは, U Extension は予約されているようです.
これは事前の調査不足だったでしょうか. しかし, https://en.wikichip.org/wiki/risc-v/standard_extensions などで調べても, U は使われていないようです.
QEMU のコード上では, target/riscv/cpu.c,target/riscv/csr.c に許容される Extension として登場しているだけのようです.
影響が読みきれないですが, 今後の課題として調査が必要そうです.

まずは, target/riscv に量子拡張を追加して QEMU 上で, ベアメタルプログラミングを行う環境を作っていく方針で進めていきます.

LLVM IR 量子拡張 (1. QIR を考える)

@k_yamaz 蛙 は, 量子コンピュータのための量子プログラミング言語や, 量子コンパイラを開発するための
OSSコミュニティ「OpenQL Project」を運営しております.
量子プログラミング言語, 量子コンパイラを開発するための調査, 検討を書いています.
OpenQL は, OpenMP や OpenCL の仕様を参考にして, 仕様を検討しています.

“A Software Methodology for Compiling Quantum Programs arXiv:1604.01401 “ による提案や
QuTechQuEST * , EPiQCによるLLVM ベースで量子拡張を目指した実装 ScaffCC など,
世界の研究機関でも同様の研究がされております.

LLVM IR の拡張

ここでは, LLVM Frontend, Backend で量子拡張することを考えています.
このためには, IR を拡張することを考える必要がありそうです.

arXiv:1604.01401 では, QIR を構成するべきという提案はありますが, 具体的な提案はされていません.
ScaffCC は, 今後実装を調べていきますが, 現状確認したところでは, IR を拡張する方針ではなく, Pass を拡張して対応しているようです.
具体的な QIR の仕様で, 公けになっている提案はみつけられていません.

IR の Instraction は, llvm/include/llvm/IR/Instruction.def に定義されています.
ここに, “1-qubit operator”, “2-qubit operator”, “measurement operator” の3つを追加すれば良いと考えられます.

具体的には, 未だどのような操作 (量子ゲート) を追加していけばよいかがはっきりしませんが, 一先ず

  • 1-qubit operator は, 任意角回転のユニタリ
  • 2-qubit operator は, CNOT
  • measurement operator は, Z軸基底の測定

として検討を進めていくことにます.

LLVM Frontend 量子拡張 (1. Qlang を考える)

@k_yamaz 蛙 は, 量子コンピュータのための量子プログラミング言語や, 量子コンパイラを開発するための
OSSコミュニティ「OpenQL Project」を運営しております.
量子プログラミング言語, 量子コンパイラを開発するための調査, 検討を書いています.
OpenQL は, OpenMP や OpenCL の仕様を参考にして, 仕様を検討しています.

“A Software Methodology for Compiling Quantum Programs arXiv:1604.01401 “ による提案や
QuTechQuEST * , EPiQCによるLLVM ベースで量子拡張を目指した実装 ScaffCC など,
世界の研究機関でも同様の研究がされております.

LLVM Frontend の拡張

LLVM Frontend である clang の量子拡張を考えます.
Frontend の名前は, 単純に qlang としておきます.

例えば, 次のようなC言語拡張を行った場合の構文解析を行えるようにしたいと考えています.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

int x = 0; // 古典変数
int a, b, c, d; // qint 型のような primitive な型を拡張する案もあるが,
// #pragma で量子変数を指定するような方法でよいのではないか

#pragma oql quantum private(a, b, c, d)
{ // プラグマによって拡張

a = 10; // initialize q-register
b = a; // 量子テレポーテーションで変数代入の処理を実現, a は破壊的
c = b; // b は破壊的
d = a; // no-cloning theorem violation ... コンパイルエラー

}
// #pragma のブロックを抜けたときに, 暗黙の測定が行われ, 測定した値が c に得られる.

x = c; // c は通常のint型として扱う.

RISC-V 量子拡張 (1. 定義を考える)

RISC-V量子拡張は, 「RiscV.RV32IU」として @k_yamaz 蛙 が提案しています.
(詳しくは, 技術ブログ Qiita に投稿した RISC-Vの量子計算拡張 をご参照ください. )
思いつきなどをメモしていきます.

RISC-Vの定義に, 量子計算拡張を追加することを考えます.
拡張ですから, 考えるのは“拡張命令”としてその拡張部分だけです.
まずは, この拡張の呼び方を考えます. 量子を示すのに都合がよさそうなQuantumの頭文字「Q」は「4倍浮動小数点」として予約されていますので使えません.
そこで量子計算に欠かせない「ユニタリ」を表す「U」の記号を当てて, 量子計算拡張は「U」として提案します.

RISC-V ISA U Extension (RISC-V 量子拡張)

とします.

RISC-V の定義は Haskell で書かれています. これに習って定義します.

量子レジスタ

1
2
3
4
5
data QRegister
= Q0
| Q1
--| Q2 | Q3 | Q4 | ... 必要とする数だけ QRegister を定義します
deriving (Show, Eq, Ord)

この量子レジスタが, どれくらいの個数必要なのかはわかりません.
ただし, 定義するだけであれば, ある程度の個数だけ定義することができます.

ユニタリ演算を表す命令セット

任意のユニタリ行列を近似的に表せる必要最低限の量子ゲートは, アダマールゲート, $\pi/8$ ゲート, 制御NOTゲートの3つでよいことが知られています.
そこで, これらの3つのユニタリ演算子と, 量子ビットを「初期化する」操作の QLEAR を定義します.

1
2
3
4
5
6
7
8
9
10
11
12
data QRegisterInstr =
QInstr !QOpcode
!CSRegister -- Control and Status Classical Register
!QRegister
deriving (Show, Eq, Ord)

data QOpcode
= QLEAR -- 量子ビットの初期化
| HADAM -- アダマール(Hadamard)ゲート
| TGATE -- π/8 ゲート(またの名は Tゲート)
| CNOT -- 制御NOTゲート(2量子ビット演算)
deriving (Show, Eq, Ord)

演算子の数を軽減するためには, 3つのユニタリ操作でよいとして必要最低限の種類を提供するだけよりは,
他のユニタリ操作も使えるように定義しておいた方がよいかもしれません.

候補としては 1〜3量子ビット演算までの量子ゲート操作がある方が良いかもしれません.
但し, これらを追加すると制御用のビット数も足らない可能性もあり, それに応じて CSRegister を引数に増やす必要があるかもしれません.

測定を表す命令セット

測定は, 上記の QRegisterInstr と同じように扱うことはできません.
なぜなら, QRegister を測定すると, その値が確定してしまいます.
その確定した値を読み出して, 古典レジスタ Register へ情報を移す必要があるからです.
つまり, QRegisterInstr とは違う QMeasurementInstr 型を定義することを考えなければなりません.
さらに測定も制御レジスタを使う前提もあり, 引数に CSRegister も含めて次のような定義とします.

1
2
3
4
5
data QMeasurementInstr =
MEASURE !CSRegister -- Control and Status Classical Register
!QRegister
!Register
deriving (Show, Eq, Ord)

この定義も一概にこれで良いのかは悩ましいです.
下記のように CSQRType とタイプを表す識別子を追加した方がよいかもしれません.
この方が「測定」だけでない他の操作を扱えるため, 汎用性がありそうです.

1
2
3
data CSQRType  = MeasureOneQubit | MeasureAll
data CSQRInstr =
CSQRInstr !CSQRType !CSRegister !QRegister !Register

この辺りもどのような定義がよいか, 今後の検討が必要になってきます.

スライドコンテンツの自動生成 (slidehtml)

  • 生成されるスライド

Slide

Hexo に generator を追加

  • Install
1
$ npm install hexo-generator-slidehtml --save

hexo-generator-slidehtml の設定

  • _config.yml の編集
1
2
3
4
slidehtml:
titleMerge: true
horizontalSeparator: '^\\n---\\n'
verticalSeparator: '^\\n--\\n'

記事を書く

  • 記事のヘッダ
1
2
3
4
---
title: hoge
slidehtml: true
---

https://[yousite]/path/to/your/article/slide.htmlが生成される.

Github Pages + Hexo の設定

Github Pages

  • アクセス制限やビルド制限など Usage limits に注意.
  • Jekyll がデフォルトなので, 最初の設定では Jekyll でサイトを構築する.
    root directory に _config.yml, _layouts/default.html (ブランチ作成時とは別の手順で作成), LICENSE, README.md, .gitignore (Jekyll) は残しておく.

Hexo

  • master repo の下に _hexo フォルダを作成してインストールする.
  • MathJax は, npm install hexo-renderer-mathjax --save でインストールする.

  • Hexo のインストール
1
$ npm install -g hexo
  • Github Pages と連携したインストール
1
2
3
4
5
6
7
8
$ git clone https://github.com/{users}/{users}.git
$ cd {users}
$ git checkout -b hexo # hexoブランチを作成
$ hexo init _hexo
$ cd _hexo
$ npm install
$ npm install hexo-deployer-git --save
$ npm install hexo-renderer-mathjax --save
  • _hexo/node_modules/hexo-renderer-mathjax/mathjax.html を編集する.

    1
    2
    -<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    +<script src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
1
2
3
$ git add .
$ git commit -m 'installed hexo'
$ git push origin hexo # remote:hexo に push
  • _config.tml を編集
  • サイト情報

    1
    2
    3
    4
    5
    6
    7
    8
    # Site
    title: How do you like Quantum ?
    subtitle: 量子計算/量子情報の徒然なブログ
    description:
    keywords: quantum computing, quantum information
    author: kyamaz
    language: ja
    timezone: Japan
  • URLの変更

    1
    2
    3
    4
    5
    # URL
    url: http://{user}.github.io/{user}
    root: /{user}/
    permalink: :year/:month/:day/:title/
    permalink_defaults:
  • deployの設定

    1
    2
    3
    4
    5
    6
    # Deployment
    deploy:
    type: git
    repo: https://github.com/{user}/{user}.git
    branch: master
    message: updated by hexo deployer

新規記事の追加

1
2
$ cd _hexo
$ hexo new post 新規ページ

( YYYYMMDD_AA_any_strings.md として管理すると便利. )

deploy 操作

master に直接 commit する. 更に, HEAD から master push される.

1
2
3
4
5
6
7
8
$ git checkout hexo

$ cd _hexo
$ hexo deploy -g

$ git add source
$ git commit -m 'updated _posts'
$ git push origin hexo