FPGA開発日記

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

Chiselを使ってCPUを作ろう(5. トレース記述をどう作る?)

Chiselを使って、非常にシンプルなCPUを作ってみるプロジェクト、ある程度演算命令は動き始めたが、ちゃんと動作しているのかどうかを確かめたい。

普通CPUを作るときは、波形をわざわざ観測するなんてそんなダサいことはしなくて、トレースファイルを出力してそれをISSと一致比較検証するか、そもそもDPIか何かを使ってCPUの内部情報を動的に抽出してISSを比較したりする。

そのために、CPUの内部にシミュレーション時限定のトレースユニットを組み込み、そこから情報を回収してテキストファイルなりなんなりに出力するわけだ。

Chiselも、一応printfなどの方法が存在している。ただし、非常に不便だ。

github.com

Chiselのシミュレーションモードで実行しているとScalaとしてこのprintfが実行される(Verilogに直すとVerilogとして実行される)が、そのフォーマットが非常にしょぼい。 まず表示幅をきちんと調整してくれない。つまり%08xとか書いても、まったく無視してくる。っていうかコンパイルが通らない。 Verilogに直してシミュレーションすると、Verilogシミュレータがちゃんと調整してくれるが、いちいちVerilogに直してられないのでScalaだけで済ませたい。

仕方が無いので、Debug情報専用のBundleを定義してそこから外部に引っ張ってくることにした。 とりあえず、

  • 命令が実行されたか (inst_valid)
  • 実行された命令アドレス(inst_addr)
  • 実行された命令(inst_addr)
  • レジスタに書き込みが発生したか(reg_wren)
  • 書き込みレジスタアドレス(reg_wraddr)
  • 書き込みレジスタデータ(reg_wrdata)

を外部に引っ張り出した。

class CpuDebugMonitor extends Bundle {
  val inst_valid = Output(Bool())
  val inst_addr  = Output(UInt(32.W))
  val inst_hex   = Output(UInt(32.W))
  val reg_wren   = Output(Bool())
  val reg_wraddr = Output(UInt(5.W))
  val reg_wrdata = Output(SInt(64.W))
}
f:id:msyksphinz:20181120011505p:plain

そして外部のTester上でScalaの記述を使ってトレースファイルを書き出す。

  for (i <- 0 to 100) {
    val inst_valid = peek(cpu_tb.io.dbg_monitor.inst_valid)
    if (inst_valid == 1) {
      val hexbus_width = 8
      writer.printf("%d : ".format(cycle))
      val reg_wren   = peek(cpu_tb.io.dbg_monitor.reg_wren)
      val reg_wraddr : Long = peek(cpu_tb.io.dbg_monitor.reg_wraddr).toLong
      val reg_wrdata : Long = peek(cpu_tb.io.dbg_monitor.reg_wrdata).toLong
      if (reg_wren == 1) {
        writer.printf("x%d<=0x%016x".format(reg_wraddr, reg_wrdata))
      } else {
        writer.printf("                     ")
      }
      val inst_addr = peek(cpu_tb.io.dbg_monitor.inst_addr)
      val inst_hex  = peek(cpu_tb.io.dbg_monitor.inst_hex)
      writer.printf(" : 0x%08x : INST(0x%08x) : DASM(%08x)\n"format(inst_addr, inst_hex, inst_hex))
    }
    step(1)
  }

printfのフォーマットもちゃんと使えるので便利だ。Chiselで記述していると、信号線は全てUIntかSIntになってしまい通常のprintfで制御できなくなる。 これをScalaのIntに変換するためにはChisel Testerのpeekを使わなければならないのだが、そのためには一度Scalaの世界に持ってこなくてはならないわけだ。

あと、64-bitの値を"%016x"で表示すると負数の時におかしな表示(マイナス付きの値)になるのでLongに変換しておくのもポイント。

これで、所望のログをファイルに出力できるようになる。

0 : x14<=0x00000000048a2b41 : 0x00000084 : INST(0xb417071b) : addiw   a4, a4, -1215
0 : x14<=0x00000048a2b41000 : 0x00000088 : INST(0x00c71713) : slli    a4, a4, 12
0 : x14<=0x00000048a2b40b11 : 0x0000008c : INST(0xb1170713) : addi    a4, a4, -1263
0 : x14<=0x00048a2b40b11000 : 0x00000090 : INST(0x00c71713) : slli    a4, a4, 12
0 : x14<=0x00048a2b40b10a21 : 0x00000094 : INST(0xa2170713) : addi    a4, a4, -1503
0 : x14<=0x48a2b40b10a21000 : 0x00000098 : INST(0x00c71713) : slli    a4, a4, 12
0 : x14<=0x48a2b40b10a2099a : 0x0000009c : INST(0x99a70713) : addi    a4, a4, -1638
0 : x15<=0xffffffffffd51000 : 0x000000a0 : INST(0xffd517b7) : lui     a5, 0xffd51
0 : x15<=0xffffffffffd50b45 : 0x000000a4 : INST(0xb457879b) : addiw   a5, a5, -1211
0 : x15<=0xfffffffaa168a000 : 0x000000a8 : INST(0x00d79793) : slli    a5, a5, 13
0 : x15<=0xfffffffaa168a219 : 0x000000ac : INST(0x21978793) : addi    a5, a5, 537
0 : x15<=0xfffea85a28864000 : 0x000000b0 : INST(0x00e79793) : slli    a5, a5, 14
0 : x15<=0xfffea85a28863d37 : 0x000000b4 : INST(0xd3778793) : addi    a5, a5, -713
0 : x15<=0xea85a28863d37000 : 0x000000b8 : INST(0x00c79793) : slli    a5, a5, 12

でも、この方式だとVerilogに変換した際に、CPUのインタフェースにデバッグ信号がそのまま出てくる。これは最終的に取り除きたいのだけれども、どうすればいいかなあ。。。

module Cpu( // @[:@569.2]
  input         clock, // @[:@570.4]
  input         reset, // @[:@571.4]
  input         io_run, // @[:@572.4]
  output [15:0] io_inst_addr, // @[:@572.4]
  output        io_inst_req, // @[:@572.4]
  input         io_inst_ack, // @[:@572.4]
  input  [31:0] io_inst_data, // @[:@572.4]
  output        io_dbg_monitor_inst_valid, // @[:@572.4]
  output [31:0] io_dbg_monitor_inst_addr, // @[:@572.4]
  output [31:0] io_dbg_monitor_inst_hex, // @[:@572.4]
  output        io_dbg_monitor_reg_wren, // @[:@572.4]
  output [4:0]  io_dbg_monitor_reg_wraddr, // @[:@572.4]
  output [63:0] io_dbg_monitor_reg_wrdata // @[:@572.4]
);

Chisel-Templateを使ってオリジナルデザインを作ってみるチュートリアル (4. ALUの実装)

随分とほったらかしにしていたが、Chiselを使ってオリジナルデザイン開発を再開した。

簡単なRISC-VコアをフルスクラッチでChiselで作ってみて、Chiselの理解を深めようと思う。

msyksphinz.hatenablog.com

各種命令の実装

まずはシンプルな算術演算命令の実装を行う。ALUの実装はまずはこの程度だ。

class Alu extends Module {
  val io = IO (new Bundle {
    val func = Input (UInt(4.W))
    val op0  = Input (SInt(64.W))
    val op1  = Input (SInt(64.W))

    val res  = Output (SInt(64.W))
  })

  val w_res = Wire(SInt(64.W))
  when (io.func === ALU_ADD) {
    w_res := io.op0 + io.op1
  } .elsewhen (io.func === ALU_SUB) {
    w_res := io.op0 - io.op1
  } .elsewhen (io.func === ALU_SLL) {
    w_res := (io.op0.asUInt << io.op1(5,0).asUInt).asSInt
  } .elsewhen (io.func === ALU_SRL) {
    w_res := (io.op0.asUInt >> io.op1(5,0).asUInt).asSInt
  } .elsewhen (io.func === ALU_SRA) {
    w_res := (io.op0 >> io.op1(5,0).asUInt).asSInt
  } .elsewhen (io.func === ALU_AND) {
    w_res := io.op0 & io.op1
  } .elsewhen (io.func === ALU_OR) {
    w_res := io.op0 | io.op1
  } .elsewhen (io.func === ALU_XOR) {
    w_res := io.op0 ^ io.op1
  } .elsewhen (io.func === ALU_SLT) {
    w_res := Mux(io.op0 < io.op1, 1.S, 0.S)
  } .elsewhen (io.func === ALU_SLTU) {
    w_res := Mux(io.op0.asUInt < io.op1.asUInt, 1.S, 0.S)
  } .elsewhen (io.func === ALU_COPY1) {
    w_res := io.op0
  } .otherwise {
    w_res := io.op0
  }

  val r_res = Reg(SInt(64.W))
  r_res := w_res
  io.res := w_res
}

2018/11/20追記。よく見てみたらChiselではcase文が使えるんだった。書き直した。

  val w_res = Wire(SInt(64.W))
  w_res := 0.S
  switch (io.func) {
    is (ALU_ADD  ) { w_res := io.op0 + io.op1                              }
    is (ALU_SUB  ) { w_res := io.op0 - io.op1                              }
    is (ALU_SLL  ) { w_res := (io.op0.asUInt << io.op1(5,0).asUInt).asSInt }
    is (ALU_SRL  ) { w_res := (io.op0.asUInt >> io.op1(5,0).asUInt).asSInt }
    is (ALU_SRA  ) { w_res := (io.op0 >> io.op1(5,0).asUInt).asSInt        }
    is (ALU_AND  ) { w_res := io.op0 & io.op1                              }
    is (ALU_OR   ) { w_res := io.op0 | io.op1                              }
    is (ALU_XOR  ) { w_res := io.op0 ^ io.op1                              }
    is (ALU_SLT  ) { w_res := Mux(io.op0 > io.op1, 1.S, 0.S)               }
    is (ALU_SLTU ) { w_res := Mux(io.op0.asUInt > io.op1.asUInt, 1.S, 0.S) }
    is (ALU_SNE  ) { w_res := Mux(io.op0 =/= io.op1, 1.S, 0.S)             }
    is (ALU_SEQ  ) { w_res := Mux(io.op0 === io.op1, 1.S, 0.S)             }
    is (ALU_SGE  ) { w_res := Mux(io.op0        > io.op1, 1.S, 0.S)        }
    is (ALU_SGEU ) { w_res := Mux(io.op0.asUInt > io.op1.asUInt, 1.S, 0.S) }
    is (ALU_COPY1) { w_res := io.op0                                       }
  }

テストパタンの作成

テストパタンは、以下のようなパタンを作ってISSと比較した。

    addi    x1, x10, 0x610
    andi    x2, x11, 0x580
    ori     x3, x12, 0x0cb
    xori    x4, x13, 0x553
    slti    x5, x14, 0x292
    sltiu   x6, x15, 0x7f5
    slli    x7, x16, 0x6
    srai    x8, x17, 0x7
    srli    x9, x18, 0x2

    sll     x1, x10, x20
    add     x2, x11, x21
    sub     x3, x12, x22
    slt     x4, x13, x23
    sltu    x5, x14, x24
    and     x6, x15, x25
    or      x7, x16, x26
    xor     x8, x17, x27
    sra     x9, x18, x28
    srl     x10, x19, x29

    addiw   x1, x10, 0x170
    slliw   x2, x11, 0xb
    srliw   x3, x12, 0xc
    sraiw   x4, x13, 0x8
    addw    x5, x14, x24
    subw    x6, x15, x25
    sllw    x7, x16, x26
    srlw    x8, x17, x27
    sraw    x9, x18, x28
f:id:msyksphinz:20181118180612p:plain

Chisel-Templateを使ってオリジナルデザインを作ってみるチュートリアル (3. CPUのコアのDebug-Trace作成)

随分とほったらかしにしていたが、Chiselを使ってオリジナルデザイン開発を再開した。

簡単なRISC-VコアをフルスクラッチでChiselで作ってみて、Chiselの理解を深めようと思う。

msyksphinz.hatenablog.com

まず、テストパタンを用意しなければならない。テストパタンはテキストファイルで作って、Scalaで読み込んでメモリに格納する。

まずはコンパイルしたプログラムを、objcopy → od でテキストファイル形式に変換する。

  • tests/simple/simple.s
_start:
    li  x1,   0
    li  x2,   1
    li  x3,   2
    li  x4,   3
    li  x5,   4
    li  x6,   5
    li  x7,   6
    li  x8,   7
...
$(TARGET).hex : $(TARGET).bin
        od -tx4 -v -w4 -Ax $^ | sed 's/^/0x/g' | gawk -F ' ' '{printf "@%08x %s\n", rshift(strtonum($$1), 2), $$2}' > $@

$(TARGET).bin : $(TARGET).elf
        riscv64-unknown-elf-objcopy --gap-fill 0 -O binary $^ $@

$(TARGET).elf : $(TARGET).s
        riscv64-unknown-elf-as $^ -o $@
  • tests/simple/test.hex
@00000000 00000093
@00000001 00100113
@00000002 00200193
@00000003 00300213
@00000004 00400293
@00000005 00500313
...

これをScalaで読み込んでメモリに格納する。

  val fp = Source.fromFile("test.hex")
  val lines = fp.getLines

  val memory = lines.map{ line =>
    val split_line = line.split(" ")
    if (split_line.length == 2) {
      Array(Integer.parseInt(line.split(" ")(0).diff("@"), 16),
        Integer.parseUnsignedInt(line.split(" ")(1), 16))
    } else {
      Array(Integer.parseInt(line.split(" ")(0).diff("@"), 16), 0)
    }
  }

ちなみに、Chiselでprintfを使うと、%xのサイズが指定できなくて苦労する。そこでPrintHex()を自分で作って桁指定のできるprintfを作ってとりあえず難をしのぐ。

object PrintHex
{
  def apply(x: UInt, length: Int): String =
  {
    require(length > 0)
    var result = ""
    for (i <- length-1 to 0 by -1) {
      printf("%x", (x >> (4.U * i.asUInt)) & 0xf.U)
    }
    result
  }

  def apply(x: SInt, length: Int): String =
  {
    require(length > 0)
    var result = ""
    for (i <- length-1 to 0 by -1) {
      printf("%x", (x.asUInt >> (4.U * i.asUInt)) & 0xf.U)
    }
    result
  }
}

これで何となくログが出てくるようになった。

f:id:msyksphinz:20181118002157p:plain

RISC-V for LLVMのビルド試行 (2. RISC-Vターゲットでのコンパイルとテスト)

f:id:msyksphinz:20181111134229p:plain

RISC-V on LLVMについて少し調べている。 LLVMソースコードを眺めていると、TargetとしてRISC-Vが追加されているのを発見した。 なんだ、追加されてるじゃないか。じゃあ動くんじゃないか。

という訳で最新版のLLVM(ver 8.0?)とClangを落としてきて、パッチを当てずにターゲットをRISC-Vにしてビルドを試行した。

mkdir build-llvm
cd build-llvm
cmake -G Ninja -DCMAKE_BUILD_TYPE="Release" -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="RISCV" ../llvm
cmake --build .

一応ビルドは成功したようだ。 テストプログラムを流してみる。まずは、オブジェクトを生成するだけ。

$ cat hello.c
int test_int(int a, int b) {
  return a + b;
}

float test_float(float a, float b) {
  return a + b;
}
$ ./bin/clang --target=riscv64-unknown-elf -O3 hello.c -c -o hello.o
fatal error: error in backend: Cannot select: 0x7fffd2df4fb8: i64 = sign_extend_inreg 0x7fffd2df4f50, ValueType:ch:i32
  0x7fffd2df4f50: i64 = add 0x7fffd2df4c78, 0x7fffd2df4ba8
    0x7fffd2df4c78: i64 = AssertSext 0x7fffd2df4ad8, ValueType:ch:i32
      0x7fffd2df4ad8: i64,ch = CopyFromReg 0x7fffd2d9fc78, Register:i64 %1
        0x7fffd2df4a70: i64 = Register %1
    0x7fffd2df4ba8: i64 = AssertSext 0x7fffd2df4a08, ValueType:ch:i32
      0x7fffd2df4a08: i64,ch = CopyFromReg 0x7fffd2d9fc78, Register:i64 %0
        0x7fffd2df49a0: i64 = Register %0
In function: test_int
clang-8: error: clang frontend command failed with exit code 70 (use -v to see invocation)
clang version 8.0.0 (https://git.llvm.org/git/clang.git/ 3919b8d9833d23d98e8be71fe608627866d5c40c) (https://git.llvm.org/git/llvm.git 20a1e3c6acad46a947e7633f39c83eb00de22ea2)
Target: riscv64-unknown-unknown-elf
Thread model: posix
InstalledDir: /home/msyksphinz/work/riscv/llvm-build/./bin
clang-8: note: diagnostic msg: PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace, preprocessed source, and associated run script.
clang-8: note: diagnostic msg:
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang-8: note: diagnostic msg: /tmp/hello-3a45a2.c
clang-8: note: diagnostic msg: /tmp/hello-3a45a2.sh
clang-8: note: diagnostic msg:

********************

うお、いきなり落ちた!まだきちんと対応していないのか?

と思ったら、よく考えたらまだriscv32の対応に限定されているのか。riscv32-unknown-elfでリコンパイルしてみる。

$ ./bin/clang --target=riscv32-unknown-elf -O3 hello.c -c -o hello.o
$ riscv64-unknown-elf-objdump -d hello.o

hello.o:     file format elf32-littleriscv


Disassembly of section .text:

00000000 <test_int>:
   0:   00a58533                add     a0,a1,a0
   4:   00008067                ret

00000008 <test_float>:
   8:   ff010113                addi    sp,sp,-16
   c:   00112623                sw      ra,12(sp)
  10:   00000097                auipc   ra,0x0
  14:   000080e7                jalr    ra
  18:   00c12083                lw      ra,12(sp)
  1c:   01010113                addi    sp,sp,16
  20:   00008067                ret

ちゃんと生成できている。と思ったらtest_floatの方は様子が変だぞ。こんなコードで浮動小数点の加算ができるはずがない。

ちゃんと-marchを指定しなきゃだめだ。

$ ./bin/clang --target=riscv32-unknown-elf -march=rv32gc -O3 hello.c -c -o hello.o
$ riscv64-unknown-elf-objdump -d hello.o

hello.o:     file format elf32-littleriscv


Disassembly of section .text:

00000000 <test_int>:
   0:   952e                    add     a0,a0,a1
   2:   8082                    ret

00000004 <test_float>:
   4:   f0058053                fmv.w.x ft0,a1
   8:   f00500d3                fmv.w.x ft1,a0
   c:   0000f053                fadd.s  ft0,ft1,ft0
  10:   e0000553                fmv.x.w a0,ft0
  14:   8082                    ret

よく考えたらこれもおかしい。なんで整数レジスタ経由で渡しているんだ?ABIを変えてみよう。

$ ./bin/clang --target=riscv32-unknown-elf -march=rv32gc -mabi=ilp32 -O3 hello.c -c -o hello.o
$ riscv64-unknown-elf-objdump -d hello.o

hello.o:     file format elf32-littleriscv


Disassembly of section .text:

00000000 <test_int>:
   0:   952e                    add     a0,a0,a1
   2:   8082                    ret

00000004 <test_float>:
   4:   f0058053                fmv.w.x ft0,a1
   8:   f00500d3                fmv.w.x ft1,a0
   c:   0000f053                fadd.s  ft0,ft1,ft0
  10:   e0000553                fmv.x.w a0,ft0
  14:   8082                    ret

それでも直らない。float経由で引数を渡すABIはあるはずだけど...

2018年のRISC-V関係の(私の)講演資料をすべて公開しました

f:id:msyksphinz:20181115000946p:plain

ずいぶんとアップロードするのを忘れていましたが、今年の予定しているRISC-V関係の講演はすべてやり切ったので、発表資料をすべて公開したいと思います。

今年は4件講演しました。秋頃から集中したのでずいぶんと息切れしました。 特にDesign Solution Forumは40分、ET & IoT Techonolgyのテクニカルセッションは90分なのでかなりきつい。

あとは、RISC-V Day WorkshopでMICRO51の会場で発表できたのは個人的にうれしかった。

RISC-V Day Workshopの資料はriscv.orgに載るはずなんですが、未だにアップロードされていないので私の資料は勝手に公開します。 RISC-V FoundationのAsia支部、どうなってんの?

  • 2018年09月12日 Design Solution Forum 2018
  • RISC-V Day Tokyo 2018, Thursday, 18 October 2018
  • IEEE Micro51 RISC-V Day 2018 Fukuoka Saturday, October 20th 2018
  • ET & IoT Techonolgy 2018 テクニカルセッションTS-3 2018/11/14

特にETのテクニカルセッションは大作。90ページ近くもあります。講演台に水を持ってくるのを忘れて声が枯れかけました。

以下発表資料。

speakerdeck.com

  • RISC-Vエコシステムを構成する技術と立役者たち
    • RISC-V Day Tokyo 2018, Thursday, 18 October 2018

speakerdeck.com

  • Introduction of Technologies and People Supporting RISC-V Ecosystem
    • IEEE Micro51 RISC-V Day 2018 Fukuoka Saturday, October 20th 2018

speakerdeck.com

  • ますます注目されるオープンCPUアーキテクチャRISC-Vの最新動向
    • ET & IoT Techonolgy 2018 テクニカルセッションTS-3 2018/11/14

speakerdeck.com

Ubuntu on Windows Subsystem for LinuxでRISC-V環境のビルド試行

f:id:msyksphinz:20181113014541p:plain

Ubuntu on Windows Subsystem for Linux上でRISC-Vのツールチェインとデザインが使えるのかどうか試行した。

なんでこんなことをしているのかというと、自宅で使っているUbuntu on Virtual Boxがクラッシュして自宅のRISC-V環境を全部失ったから。 折角なので、Windows Subsystem for Linux上でRISC-Vのツールが動作するか確かめておきたい。

時間がかかるので後で追記する。

riscv-tools

64-bit版は正常にビルド完了した。 32-bit版も正常にビルド完了した。

Rocket-Chip (とchisel)

Chiselは通常のUbuntuと同様にインストールできた。

Rocket-Chipのビルドも完了し、RTLシミュレーションは実行できた。

$ make output/dhrystone.riscv.out
mkdir -p ./output
ln -fs /home/msyksphinz/riscv64//riscv64-unknown-elf/share/riscv-tests/benchmarks/dhrystone.riscv output/dhrystone.riscv
./emulator-freechips.rocketchip.system-DefaultConfig +max-cycles=100000000 +verbose output/dhrystone.riscv 3>&1 1>&2 2>&3 | /home/msyksphinz/riscv64/bin/spike-dasm  > output/dhrystone.riscv.out && [ $PIPESTATUS -eq 0 ]
Microseconds for one run through Dhrystone: 496
Dhrystones per Second:                      2013
mcycle = 248426
minstret = 198768

Freedom-u-sdk

UbuntuのPATHが悪さをしているようだ。デフォルトだとLinuxのPATHにはWindowsの$PATH$が入り込むが、レジストリエディタを使ってこの設定を無効化する。

qiita.com

以下のエラーメッセージで落ちた。このエラーメッセージで検索すると、WSLではサポートされていないようだ。残念。

PATH="/home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/host/bin:/home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/host/sbin:/home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/host/usr/bin:/home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/host/usr/sbin:/home/msyksphinz/work/riscv/freedom-u-sdk/toolchain/bin:/home/msyksphinz/.cargo/bin:/home/msyksphinz/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin:/home/msyksphinz/software/sbt/bin/:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin:/home/msyksphinz/software/sbt/bin/" /home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/host/usr/bin/fakeroot -- /home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/build/_fakeroot.fs
fakeroot, while creating message channels: Function not implemented
This may be due to a lack of SYSV IPC support.
fakeroot: error while starting the `faked' daemon.
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
fs/tar/tar.mk:13: recipe for target '/home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/images/rootfs.tar' failed
make[2]: *** [/home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/images/rootfs.tar] Error 1
Makefile:36: recipe for target '_all' failed
make[1]: *** [_all] Error 2
make[1]: Leaving directory '/home/msyksphinz/work/riscv/freedom-u-sdk/buildroot'
Makefile:90: recipe for target '/home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/images/rootfs.tar' failed
make: *** [/home/msyksphinz/work/riscv/freedom-u-sdk/work/buildroot_initramfs/images/rootfs.tar] Error 2

Freedom-e-sdk

ダウンロードとビルド自体はできる。しかしサンプルコードをアップロードしようとすると失敗した。 デバイスドライバがまだWSLでサポートされていないらしい。 SiFiveのアカウントでも未サポートとのことらしい。

forums.sifive.com

Writing an LLVM Backendをやってみる(1. RISCV64プロジェクトを作成)

f:id:msyksphinz:20181111134229p:plain

LLVMのバックエンドについてより理解するために良さそうな資料を見つけたので一通り触ってみることにした。 Writing an LLVM Backendという。

Writing an LLVM Backend — LLVM 8 documentation

この資料では、新しいターゲットアーキテクチャを追加するにあたって何が必要なのかについて説明してある。 Target Machine Descriptionの記述から、レジスタファイルの定義、命令の定義などについて記述していく。

LLVMソースコードにはすでにRISCVターゲットのソースが入っているが、現時点では32‐bit版?しか対応していない(もしかしたら64-bitでも動くのかもしれない。ソースを眺めていると64‐bitの記述がいくつか散見される)ので、64-bit版のRISC-Vのターゲットを追加する練習をしてみようと思い立った。

lib/Target/Mipsをコピーして、lib/Target/RISCV64を作ってみることにした。 ディレクトリをコピーして、まずはMipsという記述を片っ端からRISCV64に置き換えていく。

ターゲットアーキテクチャにRISCV64を追加した。

  • lib/Target/LLVMBuild.txt
diff --git a/lib/Target/LLVMBuild.txt b/lib/Target/LLVMBuild.txt
index 0d899a9c782..33baa669987 100644
--- a/lib/Target/LLVMBuild.txt
+++ b/lib/Target/LLVMBuild.txt
@@ -33,6 +33,7 @@ subdirectories =
  Nios2
  PowerPC
  RISCV
+ RISCV64
  Sparc
  SystemZ
  WebAssembly

あとはひたすらビルドを行う。

mkdir llvm-riscv64
cd llvm-riscv64
cmake -G Ninja -DCMAKE_BUILD_TYPE="Debug" -DLLVM_TARGETS_TO_BUILD="RISCV64" ../llvm
cmake --build .

まずこれでかなりの時間を要してしまった。次から、やっとターゲットアーキテクチャ向けに改造を行っていく。