FPGA開発日記

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

LiteXによるSoC環境構築を試行する (13. LiteXのbiosブートプロセスの解析)

https://raw.githubusercontent.com/enjoy-digital/litex/master/doc/litex.png

LiteXの続き。

UARTのアドレスに対して正しくアクセスできていないように見える。まず、.dataセクションの場所を確認すると、

Disassembly of section .data:

10000000 <s_flush_cpu_dcache>:
10000000:       0d60                    .2byte  0xd60
10000002:       0000                    .2byte  0x0
10000004:       4580                    .2byte  0x4580
10000006:       0000                    .2byte  0x0
10000008:       4594                    .2byte  0x4594
1000000a:       0000                    .2byte  0x0
1000000c:       0000                    .2byte  0x0

/* ... */

10000110 <s_sdram_init>:
10000110:       4234                    .2byte  0x4234
10000112:       0000                    .2byte  0x0
10000114:       4b88                    .2byte  0x4b88
10000116:       0000                    .2byte  0x0
10000118:       4b94                    .2byte  0x4b94
1000011a:       0000                    .2byte  0x0
1000011c:       0005                    .2byte  0x5
        ...

10000120 <__stdio>:
10000120:       0000                    .2byte  0x0
10000122:       31e40003                lb      zero,798(s0)
10000126:       0000                    .2byte  0x0
10000128:       31c4                    .2byte  0x31c4
1000012a:       0000                    .2byte  0x0
1000012c:       0000                    .2byte  0x0

まず、0x1000_0000がsim_rom.initのどこに格納されているのかをチェックするが、ファイルの中を検索すると、5903行目に格納されていた。これは0x170f行目に相当し、アドレスで計算すると、0x5c3cとなる。

これによりどういう問題が発生するかというと、__stdio0x10000120のハズなのだが、$readmemh()で読まれる初期化ファイルの場所を見るとやはりずれており、単純に0x10000000にアクセスしても正しく読み込むことができない。

   5897 100000b0
   5898 100000c0
   5899 100000d0
   5900 100000e0
   5901 100000f0
   5902 10000100
   5903 10000110
   5904 00000d60  // 5903行目。つまり、0x170F x 4 = 0x5C3Cに相当している
   5905 00004580
   5906 00004594
   5907 00000000
   5908 00000e48
   5909 000045ac
   5910 000045b0
   5911 00000000

これはテストベンチ内でどのように処理されているのかをトレースしていくことにした。

これは、ブート時にdataセクションのコピーによって実現している。これにより、ROMの初期値データがSRAMに移されていく。

00000000000000d4 <data_init>:
      d4:       20000297                auipc   t0,0x20000
      d8:       f2c28293                addi    t0,t0,-212 # 20000000 <s_flush_cpu_dcache>
      dc:       20000317                auipc   t1,0x20000
      e0:       10430313                addi    t1,t1,260 # 200001e0 <_edata>
      e4:       00004397                auipc   t2,0x4
      e8:       5a438393                addi    t2,t2,1444 # 4688 <_fdata_rom>

00000000000000ec <data_loop>:
      ec:       00628963                beq     t0,t1,fe <bss_init>
      f0:       0003be03                ld      t3,0(t2)
      f4:       01c2b023                sd      t3,0(t0)
      f8:       02a1                    addi    t0,t0,8
      fa:       03a1                    addi    t2,t2,8
      fc:       bfc5                    j       ec <data_loop>

これを見ると、__stdioはこれでコピーされている。これをチェックするために、LiteX上で実行命令トレースを生成する記述を追加した。

`ifdef LITEX_SIMULATION

integer litex_log_fp;
initial begin
  litex_log_fp = $fopen ("scariv_inst.log", "w");
end

logic [riscv_pkg::XLEN_W-1: 0] w_physical_int_data [scariv_pkg::RNID_SIZE + 32];
logic [riscv_pkg::FLEN_W-1: 0] w_physical_fp_data  [scariv_pkg::RNID_SIZE + 32];
generate for (genvar r_idx = 0; r_idx < scariv_pkg::RNID_SIZE; r_idx++) begin: reg_loop
  assign w_physical_int_data[r_idx] = scariv_subsystem_wrapper.u_scariv_subsystem.u_tile.u_int_phy_registers.r_phy_regs[r_idx];
  if (riscv_pkg::FLEN_W != 0) begin
    assign w_physical_fp_data [r_idx] = scariv_subsystem_wrapper.u_scariv_subsystem.u_tile.fpu.u_fp_phy_registers.r_phy_regs[r_idx];
  end
end
endgenerate

always_ff @(negedge i_clk, negedge i_reset_n) begin
  if (!i_reset_n) begin
  end else begin
    if (o_commit.commit) begin
      for (int grp_idx = 0; grp_idx < scariv_pkg::DISP_SIZE; grp_idx++) begin
        if (o_commit.grp_id[grp_idx] &
            ~o_commit.dead_id[grp_idx]) begin
          $fwrite (litex_log_fp, "%10t (%2d,%2d) PC=0x%010x: %08x DASM(%08x)\n",
                   $time,
                   w_out_cmt_id, 1 << grp_idx,
                   w_out_entry.inst[grp_idx].pc_addr,
                   w_out_entry.inst[grp_idx].rvc_inst_valid ? w_out_entry.inst[grp_idx].rvc_inst : w_out_entry.inst[grp_idx].inst,
                   w_out_entry.inst[grp_idx].rvc_inst_valid ? w_out_entry.inst[grp_idx].rvc_inst : w_out_entry.inst[grp_idx].inst);
          $fflush (litex_log_fp);

          if (w_out_entry.inst[grp_idx].wr_reg.valid) begin
            $fwrite (litex_log_fp, "  %s[%2d](%3x) <= %016x\n",
                     w_out_entry.inst[grp_idx].wr_reg.typ == scariv_pkg::GPR ? "GPR" : "FPR",
                     w_out_entry.inst[grp_idx].wr_reg.regidx,
                     w_out_entry.inst[grp_idx].wr_reg.rnid,
                     w_out_entry.inst[grp_idx].wr_reg.typ == scariv_pkg::GPR ?
                     w_physical_int_data[w_out_entry.inst[grp_idx].wr_reg.rnid] :
                     w_physical_fp_data [w_out_entry.inst[grp_idx].wr_reg.rnid]);
          end
        end // if (o_commit.grp_id[grp_idx] &...
      end  // for (int grp_idx = 0; grp_idx < scariv_pkg::DISP_SIZE; grp_idx++)
    end  // if (w_out_valid)
  end // else: !if(!i_scariv_reset_n)
end // always_ff @ (negedge i_clk, negedge i_scariv_reset_n)

`endif //  `ifdef LITEX_SIMULATION

一応確認する。0x200001c0はちゃんとコピーされている。

2106000000 (15, 1) PC=0x00000000ec: 00628963 beq     t0, t1, pc + 18
2142000000 ( 0, 1) PC=0x00000000f0: 0003be03 ld      t3, 0(t2)
  GPR[28](24) <= 0000000000000001
2143000000 ( 1, 1) PC=0x00000000f4: 01c2b023 sd      t3, 0(t0)
2143000000 ( 1, 2) PC=0x00000000f8: 000002a1 c.addi  t0, 8
  GPR[ 5](2a) <= 00000000200001c0
2144000000 ( 2, 1) PC=0x00000000fa: 000003a1 c.addi  t2, 8
  GPR[ 7](02) <= 0000000000004848
2144000000 ( 2, 2) PC=0x00000000fc: 0000bfc5 c.j     pc - 16
  GPR[ 0](00) <= 0000000000000000
2145000000 ( 3, 1) PC=0x00000000ec: 00628963 beq     t0, t1, pc + 18
2169000000 ( 4, 1) PC=0x00000000f0: 0003be03 ld      t3, 0(t2)
  GPR[28](0a) <= 0000000000030000  // データのロード
2170000000 ( 5, 1) PC=0x00000000f4: 01c2b023 sd      t3, 0(t0)
                                   // 0x200001c0への書き込み
2170000000 ( 5, 2) PC=0x00000000f8: 000002a1 c.addi  t0, 8
  GPR[ 5](2b) <= 00000000200001c8
2171000000 ( 6, 1) PC=0x00000000fa: 000003a1 c.addi  t2, 8
  GPR[ 7](27) <= 0000000000004850
2171000000 ( 6, 2) PC=0x00000000fc: 0000bfc5 c.j     pc - 16
  GPR[ 0](00) <= 0000000000000000

しかし次のロード命令で正しく反映されていないようだ。これは波形でのデバッグが必要になりそう。

7503000000 (15, 2) PC=0x0000001c9c: 6107b503 ld      a0, 1552(a5)
  GPR[10](0a) <= 00000000200001c0
...
7946000000 ( 4, 1) PC=0x0000001e62: 00254703 lbu     a4, 2(a0)
  GPR[14](07) <= 0000000000000000  // これは0x3が読み込まれなければならない
7950000000 ( 5, 1) PC=0x0000001e66: 00853a03 ld      s4, 8(a0)
  GPR[20](2a) <= 0000000000000000