FPGA開発日記

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

FPGA開発日記 カテゴリ別インデックス

RISC-VにおけるRVWMOの仕様について読み直す

続きを読む

SpikeのPLICとCLINTの実装を確認する

最新のSpikeの実装にアップデートして、PLICとCLINTを動かすためにいろいろやってみる。

LiteXのBIOSを動かしたくて、いろいろやっている。

../spike_dpi/riscv-isa-sim/spike -l --log-commits --dtb=../dts/rv64imafdc.dtb --pc=0 -m0x0:0x100000,0x10000000:0x1000000 ../tests/litex_soc/software/bios/bios.elf

rv64imafdc.dtsは以下のようにして、PLICとCLINTを認識させている。こうしないと、SpikeがPLICとCLINTを識別してくれない。

  soc {
    #address-cells = <2>;
    #size-cells = <2>;
    compatible = "ucbbar,spike-bare-soc", "simple-bus";
    ranges;
    clint@2000000 {
      compatible = "riscv,clint0";
      interrupts-extended = <&CPU0_intc 3 &CPU0_intc 7 >;
      reg = <0x0 0x2000000 0x0 0xc0000>;
    };
    PLIC: plic@c000000 {
      compatible = "riscv,plic0";
      #address-cells = <2>;
      interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9 >;
      reg = <0x0 0xc000000 0x0 0x1000000>;
      riscv,ndev = <0x1f>;
      riscv,max-priority = <0xf>;
      #interrupt-cells = <1>;
      interrupt-controller;
    };
  };

それでも、0x5b90へのアクセスでトラップが発生してしまう。ここは、アクセス許可しているはずなんだけど...

core   0: 0x0000000000000124 (0x00628c63) beq     t0, t1, pc + 24
core   0: 3 0x0000000000000124 (0x00628c63)
core   0: 0x0000000000000128 (0x0003be03) ld      t3, 0(t2)
core   0: exception trap_load_access_fault, epc 0x0000000000000128
core   0:           tval 0x0000000000005b90
core   0: >>>>  trap_entry
core   0: 0x0000000000000020 (0xfe113c23) sd      ra, -8(sp)
core   0: 3 0x0000000000000020 (0xfe113c23) mem 0x0000000010001ff8 0x0000000000000000
core   0: 0x0000000000000024 (0xfe513823) sd      t0, -16(sp)
core   0: 3 0x0000000000000024 (0xfe513823) mem 0x0000000010001ff0 0x0000000010000000
core   0: 0x0000000000000028 (0xfe613423) sd      t1, -24(sp)
core   0: 3 0x0000000000000028 (0xfe613423) mem 0x0000000010001fe8 0x00000000100001e0
core   0: 0x000000000000002c (0xfe713023) sd      t2, -32(sp)
core   0: 3 0x000000000000002c (0xfe713023) mem 0x0000000010001fe0 0x0000000000005b90
core   0: 0x0000000000000030 (0xfca13c23) sd      a0, -40(sp)
core   0: 3 0x0000000000000030 (0xfca13c23) mem 0x0000000010001fd8 0x0000000000000000

これはいろいろ調べたら、デバイスの登録順序に基づくメモリアクセス領域のオーバラップによるものだった。

0x0000:0x10000にメモリを登録した後、ブートROMとして0x1000を登録して、0x5000あたりを検索すると0x1000のブートROMが引っかかってアクセスエラーとなる。 これの解決策としては、ハードコードされたメモリアクセス領域を無理やり変更して、自分の所望のメモリマップにするしかない。

diff --git a/riscv/mmu.cc b/riscv/mmu.cc
index 1a0c8307..8d2c8c76 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -121,9 +121,9 @@ reg_t reg_from_bytes(size_t len, const uint8_t* bytes)

 bool mmu_t::mmio_ok(reg_t paddr, access_type UNUSED type)
 {
-  // Disallow access to debug region when not in debug mode
-  if (paddr >= DEBUG_START && paddr <= DEBUG_END && proc && !proc->state.debug_mode)
-    return false;
+  // // Disallow access to debug region when not in debug mode
+  // if (addr >= DEBUG_START && addr <= DEBUG_END && proc && !proc->state.debug_mode)
+  //   return false;

   return true;
 }
diff --git a/riscv/platform.h b/riscv/platform.h
index 7fffdc84..d85e271f 100644
--- a/riscv/platform.h
+++ b/riscv/platform.h
@@ -3,7 +3,7 @@
 #define _RISCV_PLATFORM_H

 #define DEFAULT_KERNEL_BOOTARGS "console=ttyS0 earlycon"
-#define DEFAULT_RSTVEC     0x00001000
+#define DEFAULT_RSTVEC     0x20000000
 #define CLINT_BASE         0x02000000
 #define CLINT_SIZE         0x000c0000
 #define PLIC_BASE          0x0c000000
@@ -16,6 +16,6 @@
 #define NS16550_REG_IO_WIDTH 1
 #define NS16550_INTERRUPT_ID 1
 #define EXT_IO_BASE        0x40000000
-#define DRAM_BASE          0x80000000
+#define DRAM_BASE          0x00000000

 #endif
diff --git a/riscv/sim.cc b/riscv/sim.cc
index f4919c91..f005db9b 100644
--- a/riscv/sim.cc
+++ b/riscv/sim.cc
@@ -69,7 +69,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
   for (auto& x : mems)
     bus.add_device(x.first, x.second);

-  bus.add_device(DEBUG_START, &debug_module);
+  // bus.add_device(DEBUG_START, &debug_module);

   socketif = NULL;
 #ifdef HAVE_BOOST_ASIO

これで一応メモリアクセスエラーを回避して進めることができるようになった。 しかし、新しいSpikeはハードコードな部分が結構あって、面倒くさいな...

SpikeのPLICとCLINTの実装を確認する

前回の続き。exception interrupt #7というのは例外かと思っていたら割り込みだった。

つまり、この割り込みが入った時点でタイマ割り込みが掛かっていたことがわかる。 タイマ割り込みはCLINTが行うはずなので、その辺を確認してみる。

core   0: 3 0x0000000000002b2c (0x01851863)
core   0: 0x0000000000002b3c (0x00813583) ld      a1, 8(sp)
core   0: 3 0x0000000000002b3c (0x00813583) x11 0x00000000100001c0 mem 0x0000000010001e38
core   0: 0x0000000000002b40 (0x0014849b) addiw   s1, s1, 1
core   0: 3 0x0000000000002b40 (0x0014849b) x 9 0x0000000000000018
core   0: 0x0000000000002b44 (0x000b00e7) jalr    s6
core   0: 3 0x0000000000002b44 (0x000b00e7) x 1 0x0000000000002b48
core   0: >>>>  litex_putc
core   0: 0x000000000000316c (0xff010113) addi    sp, sp, -16
core   0: 3 0x000000000000316c (0xff010113) x 2 0x0000000010001e20
core   0: exception interrupt #7, epc 0x0000000000003170
core   0: >>>>  trap_entry
core   0: 0x0000000000000020 (0xfe113c23) sd      ra, -8(sp)
core   0: 3 0x0000000000000020 (0xfe113c23) mem 0x0000000010001e18 0x0000000000002b48
core   0: 0x0000000000000024 (0xfe513823) sd      t0, -16(sp)
core   0: 3 0x0000000000000024 (0xfe513823) mem 0x0000000010001e10 0x0000000010000b48
core   0: 0x0000000000000028 (0xfe613423) sd      t1, -24(sp)
core   0: 3 0x0000000000000028 (0xfe613423) mem 0x0000000010001e08 0x0000000010000b48
core   0: 0x000000000000002c (0xfe713023) sd      t2, -32(sp)
core   0: 3 0x000000000000002c (0xfe713023) mem 0x0000000010001e00 0x0000000000005d70
core   0: 0x0000000000000030 (0xfca13c23) sd      a0, -40(sp)
core   0: 3 0x0000000000000030 (0xfca13c23) mem 0x0000000010001df8 0x000000000000005f
core   0: 0x0000000000000034 (0xfcb13823) sd      a1, -48(sp)
core   0: 3 0x0000000000000034 (0xfcb13823) mem 0x0000000010001df0 0x00000000100001c0
core   0: 0x0000000000000038 (0xfcc13423) sd      a2, -56(sp)

と思ったら、最新のSpikeにはCLINTとPLICが実装されていた。気が付かなかった。 これを確認してみる。

riscv-isa-simをPC=0x0から起動するためには?

ちょっと自作CPUの検証環境を調整したくて、リセット時のPC=0として実行して検証を走らせたいのだが、どうにもSpikeがエラーを出してしまう。

0x0にブートコードを含んでいるELFをロードすると、invalid write to 0のような感じでエラーが出力して実行できない。

これを回避する方法をいろいろ調べていたのだが、どうもSpikeはデフォルトで0x0にデバッグユニットが入っていて、そこにELFを書くことはできないらしい。

bool mmu_t::mmio_ok(reg_t addr, access_type type)
{
  // Disallow access to debug region when not in debug mode
  if (addr >= DEBUG_START && addr <= DEBUG_END && proc && !proc->state.debug_mode)
    return false;

  return true;
}
#define DEBUG_START             0x0
#define DEBUG_END               (0x1000 - 1)

これをコメントアウトして、シミュレーションを実行した。

../spike_dpi/riscv-isa-sim/spike --pc=0 -l --log-commits --disable-dtb -m0x0:0x100000,0xc000000:0x400000,0x10000000:0x1000000 ../tests/litex_soc/software/bios/bios.elf

一応シミュレーションが動き始めたようだ。途中で割り込みが入っているが、入りっぱなしになっている。

core   0: 0x00000000000000a0 (0x00813f03) ld      t5, 8(sp)
core   0: 3 0x00000000000000a0 (0x00813f03) x30 0x0000000000000000 mem 0x0000000010001ec8
core   0: 0x00000000000000a4 (0x00013f83) ld      t6, 0(sp)
core   0: 3 0x00000000000000a4 (0x00013f83) x31 0x0000000000000000 mem 0x0000000010001ec0
core   0: 0x00000000000000a8 (0x08010113) addi    sp, sp, 128
core   0: 3 0x00000000000000a8 (0x08010113) x 2 0x0000000010001f40
core   0: 0x00000000000000ac (0x30200073) mret
core   0: 3 0x00000000000000ac (0x30200073) c768_mstatus 0x0000000a00000088
core   0: exception interrupt #7, epc 0x0000000000003f08
core   0: >>>>  trap_entry
core   0: 0x0000000000000020 (0xfe113c23) sd      ra, -8(sp)
core   0: 3 0x0000000000000020 (0xfe113c23) mem 0x0000000010001f38 0x0000000000001778
core   0: 0x0000000000000024 (0xfe513823) sd      t0, -16(sp)
core   0: 3 0x0000000000000024 (0xfe513823) mem 0x0000000010001f30 0x0000000010000b48
core   0: 0x0000000000000028 (0xfe613423) sd      t1, -24(sp)
core   0: 3 0x0000000000000028 (0xfe613423) mem 0x0000000010001f28 0x0000000010000b48
core   0: 0x000000000000002c (0xfe713023) sd      t2, -32(sp)
core   0: 3 0x000000000000002c (0xfe713023) mem 0x0000000010001f20 0x0000000000005d70
core   0: 0x0000000000000030 (0xfca13c23) sd      a0, -40(sp)
core   0: 3 0x0000000000000030 (0xfca13c23) mem 0x0000000010001f18 0x0000000000000880
core   0: 0x0000000000000034 (0xfcb13823) sd      a1, -48(sp)
core   0: 3 0x0000000000000034 (0xfcb13823) mem 0x0000000010001f10 0x0000000000000000
core   0: 0x0000000000000038 (0xfcc13423) sd      a2, -56(sp)
core   0: 3 0x0000000000000038 (0xfcc13423) mem 0x0000000010001f08 0x0000000000000000
core   0: 0x000000000000003c (0xfcd13023) sd      a3, -64(sp)
core   0: 3 0x000000000000003c (0xfcd13023) mem 0x0000000010001f00 0x0000000000000000
core   0: 0x0000000000000040 (0xfae13c23) sd      a4, -72(sp)
core   0: 3 0x0000000000000040 (0xfae13c23) mem 0x0000000010001ef8 0x00000000000001fe
core   0: 0x0000000000000044 (0xfaf13823) sd      a5, -80(sp)

あとは、PLICを接続するだけかな。

LiteXのBIOSソフトウェアを独自に構築する方法調査

LiteXのBIOS立ち上げ環境を、独自のRTLシミュレーション環境に移植したくて、メモしておく。

基本的に、LiteXをダウンロードしたときに登場するlitex/litex/soc/software/を丸ごと別ディレクトリに移動することになる。 さらに、ライブラリを作成するの、pythondata-software-picolibcpythondata-software-compiler_rtもコピーしておく。

LiteXのCPU環境構築用に作った、以下のファイルもすべて移動しておく。

boot-helper.S
crt0.S
csr-defs.h
irq.h
system.h

基本的にはsoftwareディレクトリでvariables.makをいじって、例えばリポジトリ管理をしているならばそこの絶対パスに置き換えるような処置をしておけばOK。これで、各ソフトウェアを順番にビルドしていけばよい。

REPO_BASE_DIR=$(shell git rev-parse --show-superproject-working-tree --show-toplevel | head -1)

PACKAGES=libc libcompiler_rt libbase libfatfs liblitespi liblitedram libliteeth liblitesdcard liblitesata bios
PACKAGE_DIRS=$(REPO_BASE_DIR)/tests/litex_soc/software/libc $(REPO_BASE_DIR)/tests/litex_soc/software/libcompiler_rt $(REPO_BASE_DIR)/tests/litex_soc/software/libbase $(REPO_BASE_DIR)/tests/litex_soc/software/libfatfs $(REPO_BASE_DIR)/tests/litex_soc/software/liblitespi $(REPO_BASE_DIR)/tests/litex_soc/software/liblitedram $(REPO_BASE_DIR)/tests/litex_soc/software/libliteeth $(REPO_BASE_DIR)/tests/litex_soc/software/liblitesdcard $(REPO_BASE_DIR)/tests/litex_soc/software/liblitesata $(REPO_BASE_DIR)/tests/litex_soc/software/bios
LIBS=libc libcompiler_rt libbase libfatfs liblitespi liblitedram libliteeth liblitesdcard liblitesata
TRIPLE=riscv64-unknown-elf
CPU=mycpu
CPUFAMILY=riscv
CPUFLAGS=-march=rv64i2p0_m     -mabi=lp64 -D__mycpu__
CPUENDIANNESS=little
CLANG=0
CPU_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/mycpu
SOC_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/
PICOLIBC_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/pythondata_software_picolibc/data
PICOLIBC_FORMAT=integer
COMPILER_RT_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/pythondata_software_compiler_rt/data
export BUILDINC_DIRECTORY
BUILDINC_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/include
LIBC_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/libc
LIBCOMPILER_RT_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/libcompiler_rt
LIBBASE_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/libbase
LIBFATFS_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/libfatfs
LIBLITESPI_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/liblitespi
LIBLITEDRAM_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/liblitedram
LIBLITEETH_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/libliteeth
LIBLITESDCARD_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/liblitesdcard
LIBLITESATA_DIRECTORY=$(REPO_BASE_DIR)/tests/litex_soc/software/liblitesata
BIOS_DIRECTORY=$(abspath $(REPO_BASE_DIR)/tests/litex_soc/software/bios)
LTO=0
BIOS_CONSOLE_FULL=1

このようなMakefileを作成して、一気通貫でビルドができるようにしておく。

all:
        $(MAKE) -C libbase
#       $(MAKE) -C libc
        $(MAKE) -C libcompiler_rt
        $(MAKE) -C libfatfs
        $(MAKE) -C liblitedram
        $(MAKE) -C libliteeth
        $(MAKE) -C liblitesata
        $(MAKE) -C liblitesdcard
        $(MAKE) -C liblitespi
        $(MAKE) -C bios

clean:
        $(MAKE) clean -C libbase
#       $(MAKE) clean -C libc
        $(MAKE) clean -C libcompiler_rt
        $(MAKE) clean -C libfatfs
        $(MAKE) clean -C liblitedram
        $(MAKE) clean -C libliteeth
        $(MAKE) clean -C liblitesata
        $(MAKE) clean -C liblitesdcard
        $(MAKE) clean -C liblitespi
        $(MAKE) clean -C bios

で、作成されたbios.elfを流してみればよいのだが、Spikeではデフォルトで動作しない。これはなんでだっけ?dtsの書き換えとか必要だったっけ。

spike -l  -m0x0:0x1000 ../tests/litex_soc/software/bios/bios.elf
Access exception occurred while loading payload ../tests/litex_soc/software/bios/bios.elf:
Memory address 0x0 is invalid

LiteXによるSoC環境構築を試行する (21. ILAを使ったデバッグ)

0x28付近でループしている。これは例外処理の部分。

0000000000000020 <trap_entry>:
      20:       fe113c23                sd      ra,-8(sp)
      24:       fe513823                sd      t0,-16(sp)
      28:       fe613423                sd      t1,-24(sp)
      2c:       fe713023                sd      t2,-32(sp)
      30:       fca13c23                sd      a0,-40(sp)
      34:       fcb13823                sd      a1,-48(sp)
      38:       fcc13423                sd      a2,-56(sp)
      3c:       fcd13023                sd      a3,-64(sp)
      40:       fae13c23                sd      a4,-72(sp)
      44:       faf13823                sd      a5,-80(sp)
      48:       fb013423                sd      a6,-88(sp)
      4c:       fb113023                sd      a7,-96(sp)
      50:       f9c13c23                sd      t3,-104(sp)
      54:       f9d13823                sd      t4,-112(sp)
      58:       f9e13423                sd      t5,-120(sp)
      5c:       f9f13023                sd      t6,-128(sp)
      60:       f8010113                add     sp,sp,-128
      64:       78d030ef                jal     3ff0 <isr>
      68:       07813083                ld      ra,120(sp)
      6c:       07013283                ld      t0,112(sp)
      70:       06813303                ld      t1,104(sp)
      74:       06013383                ld      t2,96(sp)
      78:       05813503                ld      a0,88(sp)
      7c:       05013583                ld      a1,80(sp)
      80:       04813603                ld      a2,72(sp)
      84:       04013683                ld      a3,64(sp)
      88:       03813703                ld      a4,56(sp)
      8c:       03013783                ld      a5,48(sp)
      90:       02813803                ld      a6,40(sp)
      94:       02013883                ld      a7,32(sp)
      98:       01813e03                ld      t3,24(sp)
      9c:       01013e83                ld      t4,16(sp)
      a0:       00813f03                ld      t5,8(sp)
      a4:       00013f83                ld      t6,0(sp)
      a8:       08010113                add     sp,sp,128
      ac:       30200073                mret

ずっと割り込みルーチンを回っている気がする。

0xac → 0x20 をずっと回っている気がする。

なんで0x64の飛び先が毎回変わっているんだ?

左のobjdumpでは、0x64が0x3ff0に飛んでいるが、initファイルは、

fb013423
fb113023
f9c13c23
f9d13823
f9e13423
f9f13023
f8010113
2e8040ef  # 0x64 ずれている?
07813083
07013283
06813303
06013383
05813503
05013583
04813603

なんでこれがずれるんだ?

再合成して、もう一度アセンブリコードを作り直し:

mretからの戻りが、0x10001ef8などという意味不明なアドレスからになっている。

0xac(mret)からの戻りが、どうして0x20になっているのだろう?

なんか、0x41d8の0xc002000への書き込みの時に例外が発生しているっポイ?

    41d4:       ffc6f813                and     a6,a3,-4
    41d8:       01062023                sw      a6,0(a2)
    41dc:       31c72603                lw      a2,796(a4)
    41e0:       3205a703                lw      a4,800(a1)
    41e4:       00e61a63                bne     a2,a4,41f8 <uart_write+0x54>
    41e8:       12003637                lui     a2,0x12003

0x41d8で、ST例外が発生しているようだが、tvalが0になっている。アドレス計算に失敗している?

レジスタの読み出し状況をチェックする必要がある。

オープンソースの波形ビューワSurferを試す

少し前に話題になっていたけれども、Rustで記述されたオープンソースの波形ビューワのSurferについていろいろ試行していた。

surfer-project / surfer · GitLab

これまでは基本的に波形ビューワとしてGTKwaveを使っていたのだけれども、どうにもGTKwaveも使いにくいので、こちらも試行してみようと思う。

とりあえずリリースビルドのダウンロードしてきたものは、wellenというfst読み込み用のライブラリが古くて、自作CPUの出力したfstが読み込めなかったので、wellenだけをバージョンアップしてローカルでWindows用に再ビルドした。

とりあえず、手元のfstを読み込むことができることを確認した。

ちなみに、URLを指定して波形を読み込むことができる。ただしこれはやってみると波形ファイルをダウンロードするようだ。 ダウンロードに必要な時間が生じるのは変わらない。

なるほど、波形ビューワの分割とかもできるんだな。

もうちょっとほしい機能としては、波形の複数選択とかなな。