OCamlでもできるRISC-Vシミュレータの作り方:2日目「命令デコーダ」
RISC-Vの命令のフォーマットは以下の通り。命令デコーダは命令のビット列からこれらのパラメータの切り出し処理を行い、切り出した結果を Instruction として返す。
https://gyazo.com/33535f2acea6874e3af3ac9f58ce745e
オリジナルのRubyバージョンのデコーダをほとんどそのままOCamlに持ってきた感じ。
code:instruction.ml
type t = {
opcode : int;
rd : int;
funct3 : int;
rs1 : int;
rs2 : int;
funct7 : int;
i_imm : int;
s_imm : int;
b_imm : int;
}
let decode word =
let wd = Int32.to_int word in
let opcode = wd land 0x0000007f
and rd = (wd land 0x00000f80) lsr 7
and funct3 = (wd land 0x00007000) lsr 12
and rs1 = (wd land 0x000f8000) lsr 15
and rs2 = (wd land 0x01f00000) lsr 20
and funct7 = (wd land 0xfe000000) lsr 25
and i_imm = (wd land 0xfff00000) lsr 20
and s_imm = ((wd land 0xfe000000) lsr 20) lor ((wd land 0x00000f80) lsr 7)
and b_imm =
((wd land 0x80000000) lsr 19)
lor ((wd land 0x00000080) lsl 4)
lor ((wd land 0x7e000000) lsr 20)
lor ((wd land 0x00000f00) lsr 7)
in
{ opcode; rd; funct3; rs1; rs2; funct7; i_imm; s_imm; b_imm }
命令デコーダの使い方はこんな感じ。
code:test/instruction_test.ml
(* R形式命令のデコード *)
let _ =
let word = 0b1000001_10111_10011_101_10001_0110011_l in
let inst = Rvsim.Instruction.decode word in
Printf.printf "%d\n" inst.opcode;
(* => 51 *)
Printf.printf "%d\n" inst.rd;
(* => 17 *)
Printf.printf "%d\n" inst.funct3;
(* => 5 *)
Printf.printf "%d\n" inst.rs1;
(* => 19 *)
Printf.printf "%d\n" inst.rs2;
(* => 23 *)
Printf.printf "%d\n" inst.funct7
(* => 65 *)
(* I形式命令のデコード *)
let _ =
let word = 0b100000000001_10011_101_10001_0010011_l in
let inst = Rvsim.Instruction.decode word in
Printf.printf "%d\n" inst.opcode;
(* => 19 *)
Printf.printf "%d\n" inst.rd;
(* => 17 *)
Printf.printf "%d\n" inst.funct3;
(* => 5 *)
Printf.printf "%d\n" inst.rs1;
(* => 19 *)
Printf.printf "%d\n" inst.i_imm
(* => 2049 *)
(* S形式命令のデコード *)
let _ =
let word = 0b1000001_10111_10011_101_10001_0100011_l in
let inst = Rvsim.Instruction.decode word in
Printf.printf "%d\n" inst.opcode;
(* => 35 *)
Printf.printf "%d\n" inst.funct3;
(* => 5 *)
Printf.printf "%d\n" inst.rs1;
(* => 19 *)
Printf.printf "%d\n" inst.rs2;
(* => 23 *)
Printf.printf "%d\n" inst.s_imm
(* => 2097 *)
(* B形式命令のデコード *)
let _ =
let word = 0b1_100001_10111_10011_101_1001_1_1100011_l in
let inst = Rvsim.Instruction.decode word in
Printf.printf "%d\n" inst.opcode;
(* => 99 *)
Printf.printf "%d\n" inst.funct3;
(* => 5 *)
Printf.printf "%d\n" inst.rs1;
(* => 19 *)
Printf.printf "%d\n" inst.rs2;
(* => 23 *)
Printf.printf "%d\n" inst.b_imm
(* => 7218 *)
code:test/instruction_test.expected
51
17
5
19
23
65
19
17
5
19
2049
35
5
19
23
2097
99
5
19
23
7218
テストを実行してみる。大丈夫そう。
code:sh
$ dune test && echo ok
ok
$