前回、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例外を通知するように実装してみる。