FPGA開発日記

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

LiteXのBIOSソフトウェアを独自に構築する方法調査 (2. SpikeのCLINTの動作確認)

  • CLINT : 0x02000000
  • PLIC : 0x0c000000

MIEを設定すると、タイマ割り込みがかかる。

core   0: 3 0x0000000000001760 (0x09313c23) mem 0x0000000010001fd8 0x0000000000000000
core   0: 0x0000000000001764 (0x0c0027b7) lui     a5, 0xc002
core   0: 3 0x0000000000001764 (0x0c0027b7) x15 0x000000000c002000
core   0: 0x0000000000001768 (0x0007a023) sw      zero, 0(a5)
core   0: 3 0x0000000000001768 (0x0007a023) mem 0x000000000c002000 0x00000000
core   0: 0x000000000000176c (0x30046073) csrsi   mstatus, 8
core   0: 3 0x000000000000176c (0x30046073) c768_mstatus 0x0000000a00000008
core   0: exception interrupt #7, epc 0x0000000000001770
core   0: >>>>  trap_entry
core   0: 0x0000000000000020 (0xfe113c23) sd      ra, -8(sp)
core   0: 3 0x0000000000000020 (0xfe113c23) mem 0x0000000010001f38 0x0000000000000170
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 0x0000000020000020
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)
core   0: 3 0x0000000000000044 (0xfaf13823) mem 0x0000000010001ef0 0x000000000c002000

これは誰がタイマを挿入しているのか?PLICかな? riscv-isa-simの実装を確認してみる。

最初に誰かが挿入しているようだ:

mip_csr_t::backdoor_write_with_mask(origin=00000000, mask=00000080, val=00000080).
mip_csr_t::backdoor_write_with_mask. val = 00000080
warning: tohost and fromhost symbols not in ELF; can't communicate with target
core   0: 0x0000000020000000 (0x00000297) auipc   t0, 0x0
core   0: 3 0x0000000020000000 (0x00000297) x5  0x0000000020000000
core   0: 0x0000000020000004 (0x02028593) addi    a1, t0, 32
core   0: 3 0x0000000020000004 (0x02028593) x11 0x0000000020000020
  • csrs.cc
void mip_csr_t::backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept {
  fprintf(stderr, "mip_csr_t::backdoor_write_with_mask(origin=%08lx, mask=%08lx, val=%08lx).\n",
          this->val, mask, val);
  this->val = (this->val & ~mask) | (val & mask);
  fprintf(stderr, "mip_csr_t::backdoor_write_with_mask. val = %08lx\n", this->val);
}

うーん、CLINTが最初にコンストラクタで書きに行っている。

Breakpoint 1, mip_csr_t::backdoor_write_with_mask (this=this@entry=0x555555e4f3a0, mask=mask@entry=128, val=128) at ./riscv/csrs.cc:746
746     void mip_csr_t::backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept {
(gdb) bt
#0  mip_csr_t::backdoor_write_with_mask (this=this@entry=0x555555e4f3a0, mask=mask@entry=128, val=128) at ./riscv/csrs.cc:746
#1  0x00005555558be236 in clint_t::tick (this=this@entry=0x555555e54c00, rtc_ticks=rtc_ticks@entry=0) at ./riscv/clint.cc:115
#2  0x00005555558be354 in clint_t::clint_t (this=0x555555e54c00, sim=<optimized out>, freq_hz=<optimized out>, real_time=<optimized out>) at ./riscv/clint.cc:18
#3  0x00005555558be3f0 in clint_parse_from_fdt (fdt=<optimized out>, sim=0x7fffffffc380, base=0x7fffffffb870, sargs=...) at ./riscv/clint.cc:124
#4  0x00005555558a4fcd in sim_t::sim_t (this=0x7fffffffc380, cfg=<optimized out>, halted=<optimized out>, mems=..., plugin_device_factories=..., args=..., dm_config=..., log_path=0x0, dtb_enabled=true, dtb_file=0x7fffffffd475 "../dts/rv64imafdc.dtb", socket_enabled=false, cmd_file=0x0) at ./riscv/sim.cc:165
#5  0x000055555583daef in main (argc=<optimized out>, argv=<optimized out>) at ./spike_main/spike.cc:528
    clint@2000000 {
      compatible = "riscv,clint0";
      interrupts-extended = <&CPU0_intc 3 &CPU0_intc 7 >;
      reg = <0x0 0x2000000 0x0 0xc0000>;
    };

なるほど、mtimemtimecmpが両方ともゼロで、書き込みが割り込みの挿入が行われているのか。

  • clint.cc
void clint_t::tick(reg_t rtc_ticks)
{
  if (real_time) {
   struct timeval now;
   uint64_t diff_usecs;

   gettimeofday(&now, NULL);
   diff_usecs = ((now.tv_sec - real_time_ref_secs) * 1000000) + (now.tv_usec - real_time_ref_usecs);
   mtime = diff_usecs * freq_hz / 1000000;
  } else {
    mtime += rtc_ticks;
  }

  for (const auto& [hart_id, hart] : sim->get_harts()) {
    hart->state.time->sync(mtime);
    hart->state.mip->backdoor_write_with_mask(MIP_MTIP, mtime >= mtimecmp[hart_id] ? MIP_MTIP : 0);
  }
}

とすると、CLINTのデバイスを除去すると割り込みが掛からなくなるのか?

    /*
    clint@2000000 {
      compatible = "riscv,clint0";
      interrupts-extended = <&CPU0_intc 3 &CPU0_intc 7 >;
      reg = <0x0 0x2000000 0x0 0xc0000>;
    };
    */

こうすると、一応割り込みはかからなくなった。次は、LiteXのベンチマークと自作CPUの協調動作シミュレーションで、何が違うのかを確認していこうと思う。