FPGA開発日記

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

Vivado Simulatorを使ってUVMに入門する (23. UVMを使ってランダムパタンジェネレータを作りたい)

前回はこちら:msyksphinz.hatenablog.com

UVMで色々コントロールできることが分かってきたので、今度はランダム検証に使うための要素について考えていきたい。 単純に考えられるのは、RISC-Vの命令をランダムに生成するランダムパタンジェネレータだ。

UVMのSequence ItemにRISC-Vの命令エンコーディングのフィールドを定義して、オペコードやレジスタのフィールドをランダムに変更すれば、ランダムな命令を生成できるはずだ。

とりあえず、UVMのSequence Itemを定義してみる。

  rand bit [ 6: 0] opcode;
  rand bit [ 4: 0] rd;
  rand bit [ 2: 0] funct3;
  rand bit [ 4: 0] rs1;
  rand bit [ 4: 0] rs2;
  rand bit [ 6: 0] funct7;

  // Use utility macros to implement standard functions
  // like print, copy, clane, etc
  `uvm_object_utils_begin (inst_gen_seq_item)
    `uvm_field_int (opcode, UVM_DEFAULT)
    `uvm_field_int (rd,     UVM_DEFAULT)
    `uvm_field_int (funct3, UVM_DEFAULT)
    `uvm_field_int (rs1,    UVM_DEFAULT)
    `uvm_field_int (funct7, UVM_DEFAULT)
  `uvm_object_utils_end

  function new (string name = "inst_gen_seq_item");
    super.new(name);
  endfunction // new

endclass // inst_gen_seq_item

今回は全てのフィールドをランダムにするようにしているが、別に必要な部分は後で固定する。

ポイントだけを抜き出すと、以下のドライバが命令を生成する部分だ。 一部のフィールドを固定することによって、必ずADD命令が生成されるようにしている。

    item.opcode = 'h33; // ADD
    item.funct3 = 'h0;  // ADD
    item.funct7 = 'h0;  // ADD
    `uvm_info("DRV", $sformatf("Instruction Generate : %08x DASM(%08x)",
                               {item.funct7, item.rs2, item.rs1, item.funct3, item.rd, item.opcode},
                               {item.funct7, item.rs2, item.rs1, item.funct3, item.rd, item.opcode}), UVM_LOW);
    @ (posedge vif.clk);
  endtask // drive_item

これでUVMを実行した結果が以下となった。必要な部分だけを抜き出している。spike-dasmに掛けることによって、ADD命令が生成できていることが確認できた。

$ grep Instruction xsim.log | spike-dasm 
UVM_INFO ./model/inst_gen_driver.sv(34) @ 0: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 01df8ab3 add     s5, t6, t4
UVM_INFO ./model/inst_gen_driver.sv(34) @ 200000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 010b81b3 add     gp, s7, a6
UVM_INFO ./model/inst_gen_driver.sv(34) @ 300000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 00900133 add     sp, zero, s1
UVM_INFO ./model/inst_gen_driver.sv(34) @ 400000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 01530fb3 add     t6, t1, s5
UVM_INFO ./model/inst_gen_driver.sv(34) @ 500000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 019a81b3 add     gp, s5, s9
UVM_INFO ./model/inst_gen_driver.sv(34) @ 600000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 002802b3 add     t0, a6, sp
UVM_INFO ./model/inst_gen_driver.sv(34) @ 700000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 014481b3 add     gp, s1, s4
UVM_INFO ./model/inst_gen_driver.sv(34) @ 800000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 007284b3 add     s1, t0, t2
UVM_INFO ./model/inst_gen_driver.sv(34) @ 900000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 01e081b3 add     gp, ra, t5
UVM_INFO ./model/inst_gen_driver.sv(34) @ 1000000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 00540433 add     s0, s0, t0
UVM_INFO ./model/inst_gen_driver.sv(34) @ 1100000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 002a0133 add     sp, s4, sp
UVM_INFO ./model/inst_gen_driver.sv(34) @ 1200000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 01708633 add     a2, ra, s7
UVM_INFO ./model/inst_gen_driver.sv(34) @ 1300000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 009c0633 add     a2, s8, s1
UVM_INFO ./model/inst_gen_driver.sv(34) @ 1400000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 01798d33 add     s10, s3, s7
UVM_INFO ./model/inst_gen_driver.sv(34) @ 1500000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 01480d33 add     s10, a6, s4
UVM_INFO ./model/inst_gen_driver.sv(34) @ 1600000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 001d8db3 add     s11, s11, ra
UVM_INFO ./model/inst_gen_driver.sv(34) @ 1700000: uvm_test_top.e0.a0.d0 [DRV] Instruction Generate : 01528cb3 add     s9, t0, s5