FPGA開発日記

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

Rocket-ChipのPMA検出回路を自作CPUに実装する

前回、Rocket-ChipがどのようにPMAをていぎしているのか分かったので、この構造をそのまま自作CPUに取り込みたいと思う。

前回作成した表をもとに、JSON形式でPMAの定義を作成し、これを自動的にSystemVerilog形式に落とし込むスクリプトを作った。 元となるJSONファイルはこんな感じで定義した。

[
        {
        "base": "0x0000_0000",
        "size": "0x0000_1000",
        "attr": {"R": 1, "W": 1, "X": 1, "A": 1, "C": 0},
        "comment": "Debug Controller"
    },
    {
                "base": "0x0000_3000",
        "size": "0x0000_1000",
        "attr": {"R": 1, "W": 1, "X": 1, "A": 1, "C": 0},
        "comment": "error device"
    },
    {
                "base": "0x0000_4000",
        "size": "0x0000_1000",
        "attr": {"R": 1, "W": 1, "A": 1, "X": 0, "C": 0},
        "comment":"boot ROM"
    },
    {
                "base": "0x0001_0000",
        "size": "0x0001_0000",
...

これをスクリプトで読み込ませると、こんな感じのSystemVerilogファイルを吐き出すようにした。

module pma_map (
  input logic [riscv_pkg::PADDR_W-1: 0] i_pa
  output logic o_map_hit,
  output map_attr_t o_mapt_attr_hit
);


localparam MAP_TABLE_SIZE = 11;
logic [MAP_TABLE_SIZE-1: 0] w_hit_addr;
map_attr_t w_map_attr[MAP_TABLE_SIZE];
assign w_hit_addr[ 0] = (i_pa & 'hfffffffffff000) = 'h00000000000000;  // Address Region : 0 - fff
assign w_map_attr[ 0].r = 1'b1;
assign w_map_attr[ 0].w = 1'b1;
assign w_map_attr[ 0].x = 1'b1;
assign w_map_attr[ 0].a = 1'b1;
assign w_map_attr[ 0].c = 1'b0;
assign w_hit_addr[ 1] = (i_pa & 'hfffffffffff000) = 'h00000000002000;  // Address Region : 3000 - 3fff
assign w_map_attr[ 1].r = 1'b1;
assign w_map_attr[ 1].w = 1'b1;
assign w_map_attr[ 1].x = 1'b1;
assign w_map_attr[ 1].a = 1'b1;
/* ... 途中省略 ... */
assign w_map_attr[ 9].x = 1'b0;
assign w_map_attr[ 9].a = 1'b1;
assign w_map_attr[ 9].c = 1'b0;
assign w_hit_addr[10] = (i_pa & 'hfffffff0000000) = 'h00000080000000;  // Address Region : 80000000 - 8fffffff
assign w_map_attr[10].r = 1'b1;
assign w_map_attr[10].w = 1'b1;
assign w_map_attr[10].x = 1'b1;
assign w_map_attr[10].a = 1'b1;
assign w_map_attr[10].c = 1'b1;


assign o_map_hit = |w_hit_addr;
always_comb begin
case (w_hit_addr)
  11'b00000000001 : o_map_attr = w_map_attr[0];
  11'b00000000010 : o_map_attr = w_map_attr[1];
  11'b00000000100 : o_map_attr = w_map_attr[2];
  11'b00000001000 : o_map_attr = w_map_attr[3];
  11'b00000010000 : o_map_attr = w_map_attr[4];
  11'b00000100000 : o_map_attr = w_map_attr[5];
  11'b00001000000 : o_map_attr = w_map_attr[6];
  11'b00010000000 : o_map_attr = w_map_attr[7];
  11'b00100000000 : o_map_attr = w_map_attr[8];
  11'b01000000000 : o_map_attr = w_map_attr[9];
  11'b10000000000 : o_map_attr = w_map_attr[10];
  default   : o_map_attr = 'h0;
endcase
end

endmodule

これを今度はTLBに繋げて、Memory Access例外を通知するように実装してみる。