RISC-VのLinuxブート環境を構築したので、次にこれをRTL環境で実行してみようと思う。
まずは、ブートローダをロードする前のBootROMを作成する必要がある。 SpikeやChipyardでは、BootROMが定義されており、CPUは最初にそこから命令をロードして実行する。
Chipyardの場合は、0x4000にBootROMが存在している。
L23: soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "freechips,rocketchip-unknown-soc", "simple-bus";
ranges;
L16: boot-address-reg@4000 {
reg = <0x4000 0x1000>;
reg-names = "control";
};
Spikeの場合は、0x1000にBootROMが存在している。
boot_rom.reset(new rom_device_t(rom)); bus.add_device(DEFAULT_RSTVEC, boot_rom.get());
これをRTLシミュレーションで実現しなければならない。まずは外部インタフェースに、L2と並行して仮想的なBootROMを実装した。
localparam WORDS = SIZE / (DATA_W / 8);
logic [DATA_W-1: 0] r_rom[WORDS];
logic [DATA_W-1: 0] r_rom_raw[WORDS];
assign o_req_ready = 1'b1;
logic [RD_LAT-1: 0] r_resp_valid;
logic [DATA_W-1: 0] r_resp_data[RD_LAT];
logic [TAG_W-1 : 0] r_resp_tag [RD_LAT];
always_ff @ (posedge i_clk, negedge i_reset_n) begin
if (!i_reset_n) begin
r_resp_valid[0] <= 'h0;
r_resp_data [0] <= 'h0;
r_resp_tag [0] <= 'h0;
end else begin
r_resp_valid[0] <= i_req_valid;
r_resp_data [0] <= r_rom[i_req_addr[$clog2(WORDS)-1: $clog2(DATA_W / 8)]];
r_resp_tag [0] <= i_req_tag;
end
end
generate for (genvar p_idx = 1; p_idx < RD_LAT; p_idx ++) begin : rd_loop
always_ff @ (posedge i_clk, negedge i_reset_n) begin
if (!i_reset_n) begin
r_resp_valid[p_idx] <= 'h0;
r_resp_tag [p_idx] <= 'h0;
r_resp_data [p_idx] <= 'h0;
end else begin
r_resp_valid[p_idx] <= r_resp_valid[p_idx-1];
r_resp_tag [p_idx] <= r_resp_tag [p_idx-1];
r_resp_data [p_idx] <= r_resp_data [p_idx-1];
end
end // always_ff @ (posedge i_clk, negedge i_reset_n)
end // block: rd_loop
endgenerate
assign o_resp_valid = r_resp_valid[RD_LAT-1];
assign o_resp_tag = r_resp_tag [RD_LAT-1];
assign o_resp_data = r_resp_data [RD_LAT-1];
次にBootROMの中身だが、Spikeのほうはこのようになっている。
uint32_t reset_vec[reset_vec_size] = { 0x297, // auipc t0,0x0 0x28593 + (reset_vec_size * 4 << 20), // addi a1, t0, &dtb 0xf1402573, // csrr a0, mhartid get_core(0)->get_xlen() == 32 ? 0x0182a283u : // lw t0,24(t0) 0x0182b283u, // ld t0,24(t0) 0x28067, // jr t0 0, (uint32_t) (start_pc & 0xffffffff), (uint32_t) (start_pc >> 32) };
最初のアセンブリ命令列の後に、DTBがバイナリ形式で置かれている。 まずはa1(第2引数)にDTBの位置を設定する。 次にa0(第1引数)はコア番号となる。
さらに、t0にエントリポイント(0x8000_0000)を格納してジャンプする。という要領だ。
0x8000_0000から先は当該アプリケーション(Linuxの場合はブートローダ)が走り始めることになる。
これと全く同じ環境を作成して自作のBootROMに格納し、自作CPUを立ち上げてみる。
1000 : 262 : IPC(recent) = 0.26, IPC(total) = 0.26
2000 : 598 : IPC(recent) = 0.34, IPC(total) = 0.30
3000 : 930 : IPC(recent) = 0.33, IPC(total) = 0.31
4000 : 1264 : IPC(recent) = 0.33, IPC(total) = 0.32
5000 : 1599 : IPC(recent) = 0.34, IPC(total) = 0.32
6000 : 1930 : IPC(recent) = 0.33, IPC(total) = 0.32
7000 : 2266 : IPC(recent) = 0.34, IPC(total) = 0.32
8000 : 2596 : IPC(recent) = 0.33, IPC(total) = 0.32
9000 : 2932 : IPC(recent) = 0.34, IPC(total) = 0.33
10000 : 3262 : IPC(recent) = 0.33, IPC(total) = 0.33
11000 : 3598 : IPC(recent) = 0.34, IPC(total) = 0.33
12000 : 3930 : IPC(recent) = 0.33, IPC(total) = 0.33
13000 : 4264 : IPC(recent) = 0.33, IPC(total) = 0.33
14000 : 4599 : IPC(recent) = 0.34, IPC(total) = 0.33
15000 : 4930 : IPC(recent) = 0.33, IPC(total) = 0.33
16000 : 5266 : IPC(recent) = 0.34, IPC(total) = 0.33
17000 : 5596 : IPC(recent) = 0.33, IPC(total) = 0.33
18000 : 5932 : IPC(recent) = 0.34, IPC(total) = 0.33
linux : ERROR
6000命令くらいのところまで行った。どうもDTBのロード値がおかしいらしい?RTLのロードした値が正しく、Spikeがおかしいように見える。これは解析する必要がありそうだ。
GPR[11](42) <= 0000000000000000 44113 : 6025 : PC=[000000008000c944] (M,06,01) 00354303 lbu t1, 3(a0) MR1(0x0000000000001023)=>00000000000000ed GPR[06](30) <= 00000000000000ed 44119 : 6026 : PC=[000000008000c948] (M,07,01) 00254603 lbu a2, 2(a0) MR1(0x0000000000001022)=>00000000000000fe GPR[12](38) <= 00000000000000fe 44125 : 6027 : PC=[000000008000c94c] (M,08,01) 00754883 lbu a7, 7(a0) MR1(0x0000000000001027)=>00000000000000c8 ========================================== Wrong GPR[17](10): RTL = 00000000000000cc, ISS = 00000000000000c8 ========================================== =============================== SIMULATION FINISH : FAIL (CODE=100) ===============================
