FPGA開発日記

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

RISC-VのSpike-ISSを使ったFreeRTOSの起動解析

前回の続きで、どうしても自作ISSとSpike-ISSの動作結果が一致しないところがあり、何が悪いんだろうと調べていた。

まず、spikeにはRISCV_ENABLE_COMMITLOGというログ出力用のフォーマットがある事は紹介した。 これだけでは情報としては不十分で、例えば実際にどのアドレスに対してメモリアクセスを発行したか等の情報を取得したい。 これらの情報はdefineで切ってあるわけではないので、自分で追加する必要がある。

RISC-V Spike-ISS の命令実行の仕組み

まず、RISC-V Spike-ISSはどのようにして命令をシミュレートしているのか、その仕組みを解き明かしてみる。

例えば、lw命令を実行する記述はどこに書いてあるかというと、grepしてみると以下のようなファイルを見つけることが出来る。

riscv/insns/c_lw.h
WRITE_RVC_RS2S(MMU.load_int32(RVC_RS1S + insn.rvc_lw_imm()));

一見、C++には見えないのだが、これはdefineが切りまくってあるC++だ。よく見ると、RSフィールドで指定される汎用レジスタに対して、RS1フィールド+即値フィールドを加算したアドレスでメモリアクセスした結果のデータを格納しているのが分かるだろう。

ここが気になった理由は、RISC-V 自作ISSとSpike-ISSの違いが、アドレス0x0000100cのメモリデータの違いとなって現れたからだ。

  • Spike-ISSの結果
core   0: 0x000000008000117c (0x0007a783) lw      a5, 0(a5)
3 0x000000008000117c (0x0007a783) x15 0x0000000000001020
  • 自作ISSの結果
    210822:M:MBar:[8000117c][P8000117c] 0007a783 : lw         r15,0x000(r15)       r15=>000000000000100c (000000000000100c)=>80001178 r15<=ffffffff80001178

という訳で、ロード結果はどのようにして取り扱われるのかを調べていたのだが、Spikeにおけるメモリアクセスの記述は、以下だ。

  // template for functions that load an aligned value from memory
  #define load_func(type) \
    inline type##_t load_##type(reg_t addr) { \
      if (addr & (sizeof(type##_t)-1)) \
        throw trap_load_address_misaligned(addr); \
      reg_t vpn = addr >> PGSHIFT; \
      if (likely(tlb_load_tag[vpn % TLB_ENTRIES] == vpn)) \
        return *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr); \
      if (unlikely(tlb_load_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) { \
        type##_t data = *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr); \
        if (!matched_trigger) { \
          matched_trigger = trigger_exception(OPERATION_LOAD, addr, data); \
          if (matched_trigger) \
            throw *matched_trigger; \
        } \
        return data; \
      } \
      type##_t res; \
      load_slow_path(addr, sizeof(type##_t), (uint8_t*)&res); \
      return res; \
    }

  // load value from memory at aligned address; zero extend to register width
  load_func(uint8)
  load_func(uint16)
  load_func(uint32)
  load_func(uint64)

  // load value from memory at aligned address; sign extend to register width
  load_func(int8)
  load_func(int16)
  load_func(int32)
  load_func(int64)

メチャメチャdefineが切ってあるが、C++言語だ。つまり、アクセスサイズごとにメモリ関数が定義されており、

  • アドレスアラインが間違っていれば、トラップ発生
  • TLBに引っかかれば、TLB変換
  • そうでない場合は、通常アクセス (load_slow_path)

load_slow_path()の中を見てみよう。

void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes)
{
  reg_t paddr = translate(addr, LOAD);

  if (sim->addr_is_mem(paddr)) {
    memcpy(bytes, sim->addr_to_mem(paddr), len);
    if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD))
      tracer.trace(paddr, len, LOAD);
    else
      refill_tlb(addr, paddr, LOAD);
  } else if (!sim->mmio_load(paddr, len, bytes)) {
    throw trap_load_access_fault(addr);
  }

  if (!matched_trigger) {
    reg_t data = reg_from_bytes(len, bytes);
    matched_trigger = trigger_exception(OPERATION_LOAD, addr, data);
    if (matched_trigger)
      throw *matched_trigger;
  }
}

printfデバッグ(笑)をしていくと、どうやら0x100cはaddr_is_memには引っかからないらしい。つまり特殊アドレスとして処理されるということか?

else節でMMIO_Loadが呼ばれている。

bool sim_t::mmio_load(reg_t addr, size_t len, uint8_t* bytes)
{
  if (addr + len < addr)
    return false;
  return bus.load(addr, len, bytes);
}

これはどこからロードされているんだろう?別のデバイスから引かれているんだろうか。調査要。

次に引っかかった、reg_from_bytes()を調べていくと、

reg_t reg_from_bytes(size_t len, const uint8_t* bytes)
{
  switch (len) {
    case 1:
      return bytes[0];
    case 2:
      return bytes[0] |
        (((reg_t) bytes[1]) << 8);
    case 4:
      return bytes[0] |
        (((reg_t) bytes[1]) << 8) |
        (((reg_t) bytes[2]) << 16) |
        (((reg_t) bytes[3]) << 24);
    case 8:
      return bytes[0] |
        (((reg_t) bytes[1]) << 8) |
        (((reg_t) bytes[2]) << 16) |
        (((reg_t) bytes[3]) << 24) |
        (((reg_t) bytes[4]) << 32) |
        (((reg_t) bytes[5]) << 40) |
        (((reg_t) bytes[6]) << 48) |
        (((reg_t) bytes[7]) << 56);
  }
  abort();
}

なんでこれで、mmioからロードされた値が並べられる、ということか。

RISC-V のISS "Spike"のログフォーマットを拡張する方法

f:id:msyksphinz:20170201002310j:plain

RISC-VにはUC-Berkeleyの開発した命令セットシミュレータであるSpikeが存在する。

github.com

このSpikeというシミュレータ、高速でLinuxもブートできる優れものなのだが、欠点はログがほとんど見れず、プログラムが誤作動を起こしても何が起きているのかさっぱり分からないことだった。

  • 通常起動させると基本的にログを出さない
spike riscv-spike.elf
  • -lオプションを付ける事により、標準出力にログを出すことが可能(ただしPC値と逆アセンブルコード)
spike -l riscv-spike.elf
core   0: 0x0000000080000000 (0x00002fb7) lui     t6, 0x2
core   0: 0x0000000080000004 (0x800f8f9b) addiw   t6, t6, -2048
core   0: 0x0000000080000008 (0x300f9073) csrw    mstatus, t6
core   0: 0x000000008000000c (0x0340006f) j       pc + 0x34
core   0: 0x0000000080000040 (0x00000297) auipc   t0, 0x0
core   0: 0x0000000080000044 (0x12428293) addi    t0, t0, 292
core   0: 0x0000000080000048 (0x30529073) csrw    mtvec, t0
core   0: 0x000000008000004c (0x00000093) li      ra, 0
core   0: 0x0000000080000050 (0x00000113) li      sp, 0
core   0: 0x0000000080000054 (0x00000193) li      gp, 0
core   0: 0x0000000080000058 (0x00000213) li      tp, 0
core   0: 0x000000008000005c (0x00000293) li      t0, 0
core   0: 0x0000000080000060 (0x00000313) li      t1, 0
core   0: 0x0000000080000064 (0x00000393) li      t2, 0
core   0: 0x0000000080000068 (0x00000413) li      s0, 0
core   0: 0x000000008000006c (0x00000493) li      s1, 0
core   0: 0x0000000080000070 (0x00000513) li      a0, 0
core   0: 0x0000000080000074 (0x00000593) li      a1, 0
...

これが無いと、例えば64ビットバイナリを流すときに-isa=RV64IMAをつけるのを忘れたときに、何がおきているのか分からなかったりする。

ただし、これでもレジスタの書き込み値が表示されなかったりして、詳細なデバッグをしたい時に不便だったりする。

–enable-commitlog=yesビルドオプションにてシミュレーションログを拡張する

ソースコードを眺めていると、どうやら詳細なログを出すためのdefineが切ってあるのを発見した。

      STEP_STEPPED
  } single_step;

  reg_t load_reservation;

#ifdef RISCV_ENABLE_COMMITLOG
  commit_log_reg_t log_reg_write;
  reg_t last_inst_priv;
#endif
};
...

これを有効にするのはどうしたらいいのか、いろいろ調査していくと、どうやらconfigure実行時に--enable-commitlog=yesを追加すれば有効になることが分かった。

riscv-toolsリポジトリ中のbuild-spike-only.shを改造して、--enable-commitlog=yesビルドオプションを追加しよう。

  • riscv-tools/build-spike-only.sh
diff --git a/build-spike-only.sh b/build-spike-only.sh
index ac3fda5..2673dc8 100755
--- a/build-spike-only.sh
+++ b/build-spike-only.sh
@@ -7,6 +7,6 @@
 echo "Starting RISC-V Toolchain build process"

 build_project riscv-fesvr --prefix=$RISCV
-build_project riscv-isa-sim --prefix=$RISCV --with-fesvr=$RISCV
+build_project riscv-isa-sim --prefix=$RISCV --with-fesvr=$RISCV --enable-commitlog=yes

 echo -e "\\nRISC-V Toolchain installation completed!"

このオプション付きでSpikeをビルドし直し、実行してみると以下のようにレジスタ書き込みのログが拡張された。

core   0: 0x0000000000001000 (0x7ffff297) auipc   t0, 0x7ffff
3 0x0000000000001000 (0x7ffff297) x 5 0x0000000080000000
core   0: 0x0000000000001004 (0x00028067) jr      t0
3 0x0000000000001004 (0x00028067)
core   0: 0x0000000080000000 (0x00002fb7) lui     t6, 0x2
3 0x0000000080000000 (0x00002fb7) x31 0x0000000000002000
core   0: 0x0000000080000004 (0x800f8f9b) addiw   t6, t6, -2048
3 0x0000000080000004 (0x800f8f9b) x31 0x0000000000001800
core   0: 0x0000000080000008 (0x300f9073) csrw    mstatus, t6
3 0x0000000080000008 (0x300f9073)
core   0: 0x000000008000000c (0x0340006f) j       pc + 0x34
3 0x000000008000000c (0x0340006f)
core   0: 0x0000000080000040 (0x00000297) auipc   t0, 0x0
3 0x0000000080000040 (0x00000297) x 5 0x0000000080000040
core   0: 0x0000000080000044 (0x12428293) addi    t0, t0, 292
3 0x0000000080000044 (0x12428293) x 5 0x0000000080000164
core   0: 0x0000000080000048 (0x30529073) csrw    mtvec, t0
3 0x0000000080000048 (0x30529073)
core   0: 0x000000008000004c (0x00000093) li      ra, 0
3 0x000000008000004c (0x00000093) x 1 0x0000000000000000
core   0: 0x0000000080000050 (0x00000113) li      sp, 0
3 0x0000000080000050 (0x00000113) x 2 0x0000000000000000
core   0: 0x0000000080000054 (0x00000193) li      gp, 0
3 0x0000000080000054 (0x00000193) x 3 0x0000000000000000
core   0: 0x0000000080000058 (0x00000213) li      tp, 0

ちょっと見にくいけれど、、、例えばauipc命令がx5(=t0)に即値の書き込みを発生させていることがわかるようになった。

これで、詳細なレジスタ値の遷移が読み取れるようになった。自作ISSと比較して、今の自作ISSのどこが悪いのかデバッグして行こう(やっと本来の目的に戻ってきた…)

FreeRTOSをRISC-V Spike ISSで動作させるためのオプション

しばらくFreeRTOSをRISC-Vの自作ISSや、Spikeシミュレータで動作させることが出来ず悩んでいたのだが、いつの間にかSpike-ISSに以下のオプションが追加されているのを発見した。

$ spike --help
spike: unrecognized option --help
usage: spike [host options] <target program> [target options]
Host Options:
  -p<n>                 Simulate <n> processors [default 1]
  -m<n>                 Provide <n> MiB of target memory [default 4096]
  -d                    Interactive debug mode
  -g                    Track histogram of PCs
  -l                    Generate a log of execution
  -h                    Print this help message
  -H                 Start halted, allowing a debugger to connect
  --isa=<name>          RISC-V ISA string [default RV32IMA]
  --ic=<S>:<W>:<B>      Instantiate a cache model with S sets,
  --dc=<S>:<W>:<B>        W ways, and B-byte blocks (with S and
  --l2=<S>:<W>:<B>        B both powers of 2).
  --extension=<name>    Specify RoCC Extension
  --extlib=<name>       Shared library to load
  --gdb-port=<port>  Listen on <port> for gdb to connect
  --dump-config-string  Print platform configuration string and exit

-lを追加することで、命令トレースが生成されるらしい。

$ spike -l riscv-spike.elf > riscv-spike.sw.log 2>&1

riscv-spike.sw.logを参照してみると、

warning: only got 2934964224 bytes of target mem (wanted 4026531840)
core   0: 0x0000000000001000 (0x7ffff297) auipc   t0, 0x7ffff
core   0: 0x0000000000001004 (0x00028067) jr      t0
core   0: 0xffffffff80000000 (0x00002fb7) lui     t6, 0x2
core   0: 0xffffffff80000004 (0x800f8f9b) addiw   t6, t6, -2048
core   0: exception trap_illegal_instruction, epc 0xffffffff80000004
core   0: 0x0000000000001010 (0x00000000) addi    s0, sp, 0
core   0: exception trap_illegal_instruction, epc 0x0000000000001010
...

ん?すぐに例外に飛んでしまった。しかもaddiwということは実行モードが間違っているのか?

  --isa=<name>          RISC-V ISA string [default RV32IMA]

そうだ!デフォルトでは32ビットモードになっているのか!という訳で--isa=RV64IMAを追加してみた。

$ spike --isa=RV64IMA riscv-spike.elf
warning: only got 2934964224 bytes of target mem (wanted 4026531840)
PASS!

おー、ちゃんとパスした!ということは、Makefileが間違っているんじゃん!

sim:
-    spike $(PROG).elf
+    spike --isa=RV64IMA $(PROG).elf

資格試験(TOEIC)の勉強をRedmineで管理してみる試行

TOEIC受けてきた。毎年1度は受験するようにしているのだが、今回は比較的大きな会場だったのだが、音響もしっかりしている分、聞き取りにくいということは無かった。

去年の春からTOEICは新形式になっており、一応勉強はしていたのだがやはり時間配分や問題の難易度が変わっており、少し対応が難しく感じた。 まあこれも慣れかな。新形式になって10年、また少しずつ対応していけばよいと思う。 まあ今回の試験は黒歴史として葬り去られるかもしれない(笑)。

さて、今回はちょっとした挑戦として、TOEICの試験勉強をRedmineで管理してみた。 目的としては、複数の教科書で漏れが無いように勉強するためだ。

f:id:msyksphinz:20170129205639p:plain

少し感覚を空けて問題集をリトライする時でも、どこまでやっていたかを記録しているし、進捗もガントチャートで表示できるので、まあまあ良いんじゃないかな。 ほかの勉強でも、Redmineで管理してみよう。

「アジャイルサムライ」を(とりあえず)読了した

アジャイルサムライ−達人開発者への道−

アジャイルサムライ−達人開発者への道−

アジャイルプロジェクトというのに昔から興味があって、「アジャイルサムライ」というのを読み始めていた。

アジャイルサムライについては前に少しブログで触れたけれども、この度やっと一通り読み終えたので、全体を通して思ったことをまとめておきたい。

msyksphinz.hatenablog.com

お客との対話が常に重要

アジャイルサムライでは、要求や締め切りをミートさせるために、お客と常に話し合うことが大事だとまず説いていた。 プロジェクトにお客を巻き込むのだと。 そして、短いスパンでリリースを繰り返して行き、顧客の思うものと、最終成果物との差分をなくしていくことが重要だ。 また、常にプロジェクトのありのままをお客に見てもらうことにより、プロジェクトに問題が発生しても正しい解決策を導き出すことが出来るようになる。

これ、ハードウェアや半導体開発でも同じことが言えるだろう。ハードウェア開発者にとって、お客というのは実際にチップを使うメーカーであったり、 同じプロジェクト内にいるソフトウェア技術者だったりする。

ソフトウェア技術者に対して、細かくFPGAで最新ハードウェアをリリースしチェックしてもらうことは、常にゴールをぶれさせないようにするためであったり、 後に述べる「継続的インテグレーション」のために必要なことだと思う。

面白いツールの紹介「インセプションデッキ」

よくプロジェクトの途中に、自分の役割が良く分からなくなったり、目標がぼやけてしまうことがある。

そのためにまずはアジャイルプロジェクトでは「このプロジェクトの視界を遮る難しい問題」についてあえて取り上げ、プロジェクトをスムーズに進めるための 手助けとする。これはエンジニアにとって、「今自分の仕事は何のためにあるのか」という重要なモチベーションを維持するのに役に立つ。

f:id:msyksphinz:20170128194911p:plain

面白いツールの紹介「バーンダウンチャート」

プロジェクトの進捗度合い、ベロシティが今どの程度なのか?それを見積もるためのツールとしてバーンダウンチャートが紹介されていた。

どの程度タスクをこなしたかにより、現在のベロシティと完了見積もりをたてることが出来る。

タスクが増えたことにより、見積もりが変わった場合にはベロシティを考え直し、プロジェクトの終了見積もりを立て直す。

f:id:msyksphinz:20170128200956p:plain

おまけ:第V部の個人メモ

第5部については、読みながらRedmineにメモを取っていったので、それを貼っておこうと思う。

第12章 ユニットテスト:動くことが分かる

  • バグを修正する前に、失敗するテストを書く。

テストコードをたくさん書くことの利点

  • すばやいフィードバックが得られる
  • きわめて低コストにリグレッションテストを実行できる
  • デバッグ時間を大幅に削減できる
  • 自信を持ってデプロイできる

一見ユニットテストを書くのが難しそうな項目(ランダムテストであることを確認するテストなど)でも、アサーションなどを適用することにより、ある程度チェックすることが出来る。

第13章 リファクタリング:技術的負債の返済

  • 新機能の追加はしないし、バグの修正もしない。もっと分かりやすくする。
  • コードの意図をつかみやすくしたり、変更がしやすくなるように設計を改善する→リファクタリング

第14章 テスト駆動開発

ごく短いサイクルを繰り返しながら少しずつソフトウェアを設計していく。

  1. まずは失敗するユニットテストを書く
  2. テストに成功するコードを書く
  3. リファクタリングする

以上を繰り返す。

  • ルールその1。失敗するテストをひとつ書くまでは、新しいコードを一切書かない。
  • ルールその2。「危なっかしいところ」をすべてテストする。

第15章 継続的インテグレーション:リリースに備える

  • 常にリリースできるような状態を維持する。
  • チェックイン手順を習慣付ける
  • ビルドの作業単位を短くし、短いスパンで継続的インテグレーションできるように心がける。

RISC-VのJavascriptエミュレータはC言語から生成されている

前回の続き。RISC-Vエミュレータであるriscvemuのコンパイルオプションを調べていたのだが、やっと意味が分かってきた。

riscvemuのディレクトリにはjs/が入っており、RISC-VのJavascriptエミュレータが入っている。 最初はC言語からこのJavascript記述を呼び出しているのかと思ったが、その逆だった。C言語の記述から、Javascriptのファイルを生成していたのだ。

考えてみれば、これは当然のことだ。EmscriptenC言語記述からJavascriptを生成するものだ。なのでWebで動作するRISC-VエミュレータEmscriptenで生成しているのも納得できる。

Makefile.jsに生成スクリプトが格納されていた。

# build Javascript version of riscvemu
EMCC=emcc
EMCFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -MMD -fno-strict-aliasing
#EMCFLAGS+=-Werror
EMCFLAGS+=-DMAX_XLEN=64
EMLDFLAGS=-g -O3 -s TOTAL_MEMORY=536870912 --memory-init-file 0 --closure 0 -s NO_EXIT_RUNTIME=1 -s "EXPORTED_FUNCTIONS=['_console_queue_char','_main']"

all: js/riscvemu.js

JS_OBJS=riscvemu.js.o softfp.js.o ide.js.o

js/riscvemu.js: $(JS_OBJS)
        $(EMCC) $(EMLDFLAGS) -o $@ $(JS_OBJS)

%.js.o: %.c
        $(EMCC) $(EMCFLAGS) -c -o $@ $<

以下で実行してみた。

$ make -f Makefile.js
emcc -O2 -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -MMD -fno-strict-aliasing -DMAX_XLEN=64 -c -o riscvemu.js.o riscvemu.c
INFO:root:generating system asset: is_vanilla.txt... (this will be cached in "/home/vagrant/.emscripten_cache/is_vanilla.txt" for subsequent builds)
INFO:root: - ok
INFO:root:(Emscripten: Running sanity checks)
riscvemu.c:495:1: warning: unused function 'phys_read_u8' [-Wunused-function]
PHYS_MEM_READ_WRITE(8, uint8_t)
^
riscvemu.c:486:25: note: expanded from macro 'PHYS_MEM_READ_WRITE'
static inline uint_type phys_read_u ## size(RISCVCPUState *s, target_ulong addr) \
                        ^
<scratch space>:9:1: note: expanded from here
phys_read_u8
^
1 warning generated.
emcc -O2 -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -MMD -fno-strict-aliasing -DMAX_XLEN=64 -c -o softfp.js.o softfp.c
emcc -O2 -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -MMD -fno-strict-aliasing -DMAX_XLEN=64 -c -o ide.js.o ide.c
emcc -g -O3 -s TOTAL_MEMORY=536870912 --memory-init-file 0 --closure 0 -s NO_EXIT_RUNTIME=1 -s "EXPORTED_FUNCTIONS=['_console_queue_char','_main']" -o js/riscvemu.js riscvemu.js.o softfp.js.o ide.js.o
INFO:root:generating system library: libc.bc... (this will be cached in "/home/vagrant/.emscripten_cache/asmjs/libc.bc" for subsequent builds)

INFO:root: - ok
INFO:root:generating system library: dlmalloc.bc... (this will be cached in "/home/vagrant/.emscripten_cache/asmjs/dlmalloc.bc" for subsequent builds)
INFO:root: - ok
warning: Output contains some very large functions (3671 lines in _riscv_cpu_interp64), consider building source files with -Os or -Oz, and/or trying OUTLINING_LIMIT to break them up (see settings.js; note that the parameter there affects AST nodes, while we measure lines here, so the two may not match up)

RISCVEMU(高速RISC-Vエミュレータ)には2つのビルドモードがある(Emscriptenの調査)

RISCVEMUは高速RISC-Vエミュレータだが、その実装の仕組みを探っていると、どうやら2つのビルドモードがありそうだということが分かった。

msyksphinz.hatenablog.com

RISCVEMUはLinuxも立ち上げることが出来る高速エミュレータだが、その実装の仕組みを探っていると、大きくソースコード#defineにより分割されていることが分かった。

  • risvemu.c
#ifdef EMSCRIPTEN
#include "list.h"
#include <emscripten.h>
#else
#include <getopt.h>
#include <termios.h>
#endif

EMSCRIPTENというのは何だろうと思ったが、どうやらC言語Javascriptを接続するためのツールらしい。

デフォルトでは、このEMSCRIPTENはオフになっており、C言語でごりごりに記述されたRISCVエミュレータが起動する。

  • riscvemu_template.h
        switch(opcode) {
#ifdef CONFIG_EXT_C
        C_QUADRANT(0)
            pc_next = (intx_t)(s->pc + 2);
...
            }
            if (rd != 0)
                s->reg[rd] = val;
            break;
#if XLEN >= 64
        case 0x3b: /* OP-32 */
            imm = insn >> 25;
            val = s->reg[rs1];
            val2 = s->reg[rs2];
            if (imm == 1) {
                funct3 = (insn >> 12) & 7;
                switch(funct3) {
                case 0: /* mulw */
                    val = (int32_t)((int32_t)val * (int32_t)val2);
                    break;
                case 4:/* divw */
                    val = div32(val, val2);
                    break;
                case 5:/* divuw */
                    val = (int32_t)divu32(val, val2);
                    break;
                case 6:/* remw */
                    val = rem32(val, val2);
                    break;
                case 7:/* remuw */
                    val = (int32_t)remu32(val, val2);
                    break;
                default:
                    goto illegal_insn;
                }
            } else {
                if (imm & ~0x20)
                    goto illegal_insn;
                funct3 = ((insn >> 12) & 7) | ((insn >> (30 - 3)) & (1 << 3));
                switch(funct3) {
                case 0: /* addw */
                    val = (int32_t)(val + val2);
                    break;
                case 0 | 8: /* subw */

EMSCRIPTENを有効にすると、Javascriptでの実装が有効になるみたいなのだが、このためにはEmscriptenのインストールが必要になる。

qiita.com

Download and install — Emscripten 1.36.14 documentation

emscripten.h — Emscripten 1.36.14 documentation

上記のウェブサイトの指示の元にインストールしてみたのだが、上手くいかなかった。

/emsdk_portable$ sudo ./emsdk install latest
Installing SDK 'sdk-master-64bit'..
Installing tool 'clang-master-64bit'..
Repository 'https://github.com/kripken/emscripten-fastcomp/' already cloned to directory '/home/vagrant/work/emsdk_portable/clang/fastcomp/src', skipping.
Fetching latest changes to the branch 'master' for '/home/vagrant/work/emsdk_portable/clang/fastcomp/src'...
Already up-to-date.
Successfully updated and checked out branch 'master' on repository '/home/vagrant/work/emsdk_portable/clang/fastcomp/src'
Current repository version: "Fri, 23 Dec 2016 15:47:53 -0800 881bd352731d21c7117ad7e2ece347aacae83965"
Repository 'https://github.com/kripken/emscripten-fastcomp-clang/' already cloned to directory '/home/vagrant/work/emsdk_portable/clang/fastcomp/src/tools/clang', skipping.
Fetching latest changes to the branch 'master' for '/home/vagrant/work/emsdk_portable/clang/fastcomp/src/tools/clang'...
Already up-to-date.
Successfully updated and checked out branch 'master' on repository '/home/vagrant/work/emsdk_portable/clang/fastcomp/src/tools/clang'
Current repository version: "Fri, 23 Dec 2016 15:47:47 -0800 60a7e9a9c22b67309e5b1258d38fadfa481a25d3"
Running CMake: ['cmake', '-G', 'Unix Makefiles', '-DCMAKE_BUILD_TYPE=Release', '-DPYTHON_EXECUTABLE=/usr/bin/python', '-DLLVM_TARGETS_TO_BUILD=X86;JSBackend', '-DLLVM_INCLUDE_EXAMPLES=OFF', '-DCLANG_INCLUDE_EXAMPLES=OFF', '-DLLVM_INCLUDE_TESTS=OFF', '-DCLANG_INCLUDE_TESTS=OFF', '/home/vagrant/work/emsdk_portable/clang/fastcomp/src']
CMake Error at CMakeLists.txt:3 (cmake_minimum_required):
  CMake 3.4.3 or higher is required.  You are running version 3.2.2


-- Configuring incomplete, errors occurred!
CMake invocation failed due to exception!
Working directory: /home/vagrant/work/emsdk_portable/clang/fastcomp/build_master_64
Command '['cmake', '-G', 'Unix Makefiles', '-DCMAKE_BUILD_TYPE=Release', '-DPYTHON_EXECUTABLE=/usr/bin/python', '-DLLVM_TARGETS_TO_BUILD=X86;JSBackend', '-DLLVM_INCLUDE_EXAMPLES=OFF', '-DCLANG_INCLUDE_EXAMPLES=OFF', '-DLLVM_INCLUDE_TESTS=OFF', '-DCLANG_INCLUDE_TESTS=OFF', '/home/vagrant/work/emsdk_portable/clang/fastcomp/src']' returned non-zero exit status 1
Installation failed!

まずはCMakeの最新版をダウンロードしてきた。

wget https://cmake.org/files/v3.7/cmake-3.7.2-Linux-x86_64.tar.gz

CMakeを最新版にアップデートしてemsdk insntall latestを実行すると前に進みだしたようだ。

これにはもうちょっと時間がかかる。今日は時間切れ。