diff --git a/dv/uvm/common/irq_agent/irq_agent_pkg.sv b/dv/uvm/common/irq_agent/irq_agent_pkg.sv new file mode 100644 index 00000000..84ec32c4 --- /dev/null +++ b/dv/uvm/common/irq_agent/irq_agent_pkg.sv @@ -0,0 +1,23 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "irq_if.sv" + +package irq_agent_pkg; + + import uvm_pkg::*; + + parameter DATA_WIDTH = 32; + parameter ADDR_WIDTH = 32; + + `include "uvm_macros.svh" + `include "irq_seq_item.sv" + + typedef uvm_sequencer#(irq_seq_item) irq_master_sequencer; + + `include "irq_monitor.sv" + `include "irq_master_driver.sv" + `include "irq_master_agent.sv" + +endpackage diff --git a/dv/uvm/common/irq_agent/irq_if.sv b/dv/uvm/common/irq_agent/irq_if.sv new file mode 100644 index 00000000..0c486883 --- /dev/null +++ b/dv/uvm/common/irq_agent/irq_if.sv @@ -0,0 +1,12 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +interface irq_if; + logic clock; + logic reset; + logic irq_i; + logic [4:0] irq_id_i; + logic [4:0] irq_id_o; + logic irq_ack_o; +endinterface diff --git a/dv/uvm/common/irq_agent/irq_master_agent.sv b/dv/uvm/common/irq_agent/irq_master_agent.sv new file mode 100644 index 00000000..0c2343c3 --- /dev/null +++ b/dv/uvm/common/irq_agent/irq_master_agent.sv @@ -0,0 +1,29 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class irq_master_agent extends uvm_agent; + + irq_master_driver driver; + irq_master_sequencer sequencer; + irq_monitor monitor; + + `uvm_component_utils(irq_master_agent) + `uvm_component_new + + virtual function void build_phase(uvm_phase phase); + super.build_phase(phase); + monitor = irq_monitor::type_id::create("monitor", this); + if (get_is_active() == UVM_ACTIVE) begin + driver = irq_master_driver::type_id::create("driver", this); + sequencer = irq_master_sequencer::type_id::create("sequencer", this); + end + endfunction : build_phase + + function void connect_phase(uvm_phase phase); + if (get_is_active() == UVM_ACTIVE) begin + driver.seq_item_port.connect(sequencer.seq_item_export); + end + endfunction : connect_phase + +endclass : irq_master_agent diff --git a/dv/uvm/common/irq_agent/irq_master_driver.sv b/dv/uvm/common/irq_agent/irq_master_driver.sv new file mode 100644 index 00000000..4339a0dc --- /dev/null +++ b/dv/uvm/common/irq_agent/irq_master_driver.sv @@ -0,0 +1,66 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class irq_master_driver extends uvm_driver #(irq_seq_item); + + // The virtual interface used to drive and view HDL signals. + protected virtual irq_if vif; + + `uvm_component_utils(irq_master_driver) + `uvm_component_new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + if (!uvm_config_db#(virtual irq_if)::get(this, "", "vif", vif)) begin + `uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"}); + end + endfunction: build_phase + + virtual task run_phase(uvm_phase phase); + fork + get_and_drive(); + reset_signals(); + join + endtask : run_phase + + virtual protected task get_and_drive(); + @(negedge vif.reset); + forever begin + seq_item_port.try_next_item(req); + if (req != null) begin + $cast(rsp, req.clone()); + rsp.set_id_info(req); + drive_seq_item(rsp); + seq_item_port.item_done(rsp); + end else begin + @(posedge vif.clock); + end + end + endtask : get_and_drive + + virtual protected task reset_signals(); + forever begin + @(posedge vif.reset); + vif.irq_i <= 'h0; + vif.irq_id_i <= 'hz; + end + endtask : reset_signals + + virtual protected task drive_seq_item (irq_seq_item trans); + if (trans.delay > 0) begin + repeat(trans.delay) @(posedge vif.clock); + end + vif.irq_i <= 1'b1; + vif.irq_id_i <= trans.irq_id; + @(posedge vif.clock); + while (vif.irq_ack_o !== 1'b1) begin + @(posedge vif.clock); + end + trans.irq_id_o = vif.irq_id_o; + vif.irq_i <= 'h0; + vif.irq_id_i <= 'hz; + endtask : drive_seq_item + +endclass : irq_master_driver + diff --git a/dv/uvm/common/irq_agent/irq_monitor.sv b/dv/uvm/common/irq_agent/irq_monitor.sv new file mode 100644 index 00000000..b08e760b --- /dev/null +++ b/dv/uvm/common/irq_agent/irq_monitor.sv @@ -0,0 +1,41 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class irq_monitor extends uvm_monitor; + + protected virtual irq_if vif; + + uvm_analysis_port#(irq_seq_item) irq_port; + + `uvm_component_utils(irq_monitor) + + function new(string name, uvm_component parent=null); + super.new(name, parent); + irq_port = new("irq_port", this); + endfunction : new + + function void build_phase(uvm_phase phase); + if (!uvm_config_db#(virtual irq_if)::get(this, "", "vif", vif)) begin + `uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"}); + end + endfunction: build_phase + + virtual task run_phase(uvm_phase phase); + collect_irq(); + endtask : run_phase + + virtual protected task collect_irq(); + irq_seq_item irq; + forever begin + irq = irq_seq_item::type_id::create("irq"); + while (vif.irq_i === 1'b0) @(posedge vif.clock); + irq.irq_id = vif.irq_id_i; + while (vif.irq_ack_o === 1'b0) @(posedge vif.clock); + irq.irq_id_o = vif.irq_id_o; + irq_port.write(irq); + @(posedge vif.clock); + end + endtask : collect_irq + +endclass : irq_monitor diff --git a/dv/uvm/common/irq_agent/irq_seq_item.sv b/dv/uvm/common/irq_agent/irq_seq_item.sv new file mode 100644 index 00000000..403c5a87 --- /dev/null +++ b/dv/uvm/common/irq_agent/irq_seq_item.sv @@ -0,0 +1,19 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class irq_seq_item extends uvm_sequence_item; + + rand bit [4:0] irq_id; + rand bit [3:0] delay; + rand bit [4:0] irq_id_o; + + `uvm_object_utils_begin(irq_seq_item) + `uvm_field_int(irq_id, UVM_DEFAULT) + `uvm_field_int(irq_id_o, UVM_DEFAULT) + `uvm_field_int(delay, UVM_DEFAULT) + `uvm_object_utils_end + + `uvm_object_new + +endclass : irq_seq_item diff --git a/dv/uvm/env/core_ibex_dut_probe_if.sv b/dv/uvm/env/core_ibex_dut_probe_if.sv index 3c26d957..d285b7f2 100644 --- a/dv/uvm/env/core_ibex_dut_probe_if.sv +++ b/dv/uvm/env/core_ibex_dut_probe_if.sv @@ -7,4 +7,5 @@ interface core_ibex_dut_probe_if(input logic clk); logic illegal_instr; logic ecall; logic fetch_enable; + logic debug_req; endinterface diff --git a/dv/uvm/ibex_dv.f b/dv/uvm/ibex_dv.f index e22e2b17..7c55d045 100644 --- a/dv/uvm/ibex_dv.f +++ b/dv/uvm/ibex_dv.f @@ -30,12 +30,14 @@ ${PRJ_DIR}/ibex/rtl/ibex_core.sv +incdir+${PRJ_DIR}/ibex/dv/uvm/env +incdir+${PRJ_DIR}/ibex/dv/uvm/tests +incdir+${PRJ_DIR}/ibex/dv/uvm/common/ibex_mem_intf_agent ++incdir+${PRJ_DIR}/ibex/dv/uvm/common/irq_agent +incdir+${PRJ_DIR}/ibex/dv/uvm/common/mem_model +incdir+${PRJ_DIR}/ibex/dv/uvm/common/utils ${PRJ_DIR}/ibex/dv/uvm/common/utils/clk_if.sv ${PRJ_DIR}/ibex/dv/uvm/common/utils/dv_utils_pkg.sv ${PRJ_DIR}/ibex/dv/uvm/common/mem_model/mem_model_pkg.sv ${PRJ_DIR}/ibex/dv/uvm/common/ibex_mem_intf_agent/ibex_mem_intf_agent_pkg.sv +${PRJ_DIR}/ibex/dv/uvm/common/irq_agent/irq_agent_pkg.sv ${PRJ_DIR}/ibex/dv/uvm/env/core_ibex_env_pkg.sv ${PRJ_DIR}/ibex/dv/uvm/tests/core_ibex_test_pkg.sv ${PRJ_DIR}/ibex/dv/uvm/tb/core_ibex_tb_top.sv diff --git a/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py b/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py index 7cfc50a6..547a822d 100644 --- a/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py +++ b/dv/uvm/riscv_dv_extension/ibex_log_to_trace_csv.py @@ -6,6 +6,9 @@ import argparse import re +import sys + +sys.path.insert(0, "../../vendor/google_riscv-dv/scripts") from riscv_trace_csv import * diff --git a/dv/uvm/tb/core_ibex_tb_top.sv b/dv/uvm/tb/core_ibex_tb_top.sv index 380ebd0f..58762b71 100644 --- a/dv/uvm/tb/core_ibex_tb_top.sv +++ b/dv/uvm/tb/core_ibex_tb_top.sv @@ -20,17 +20,16 @@ module core_ibex_tb_top; .core_id_i('0), .cluster_id_i('0), .boot_addr_i(`BOOT_ADDR), // align with spike boot address - .irq_i('0), - .irq_id_i('0), .debug_req_i('0), .fetch_enable_i(fetch_enable) ); - ibex_mem_intf data_mem_vif(); - ibex_mem_intf instr_mem_vif(); + ibex_mem_intf data_mem_vif(); + ibex_mem_intf instr_mem_vif(); + irq_if irq_vif(); initial begin - //data load/store vif connection + // Data load/store vif connection force data_mem_vif.clock = clk; force data_mem_vif.reset = ~rst_n; force data_mem_vif.request = dut.data_req_o; @@ -42,7 +41,7 @@ module core_ibex_tb_top; force data_mem_vif.wdata = dut.data_wdata_o; force dut.data_rdata_i = data_mem_vif.rdata; force dut.data_err_i = 0; // TODO(taliu) Support interface error - //instruction fetch vif connnection + // Instruction fetch vif connnection force instr_mem_vif.clock = clk; force instr_mem_vif.reset = ~rst_n; force instr_mem_vif.request = dut.instr_req_o; @@ -53,18 +52,27 @@ module core_ibex_tb_top; force dut.instr_rvalid_i = instr_mem_vif.rvalid; force instr_mem_vif.addr = dut.instr_addr_o; force dut.instr_rdata_i = instr_mem_vif.rdata; + // IRQ interface + force irq_vif.clock = clk; + force irq_vif.reset = ~rst_n; + force dut.irq_i = irq_vif.irq_i; + force dut.irq_id_i = irq_vif.irq_id_i; + force irq_vif.irq_ack_o = dut.irq_ack_o; + force irq_vif.irq_id_o = dut.irq_id_o; end // DUT probe interface core_ibex_dut_probe_if dut_if(.clk(clk)); assign dut_if.ecall = dut.id_stage_i.ecall_insn_dec; assign fetch_enable = dut_if.fetch_enable; + assign dut_if.debug_req = dut.debug_req_i; initial begin uvm_config_db#(virtual clk_if)::set(null, "*", "clk_if", ibex_clk_if); uvm_config_db#(virtual core_ibex_dut_probe_if)::set(null, "*", "dut_if", dut_if); uvm_config_db#(virtual ibex_mem_intf)::set(null, "*data_if_slave*", "vif", data_mem_vif); uvm_config_db#(virtual ibex_mem_intf)::set(null, "*instr_if_slave*", "vif", instr_mem_vif); + uvm_config_db#(virtual irq_if)::set(null, "*", "vif", irq_vif); run_test(); end diff --git a/dv/uvm/tests/core_ibex_base_test.sv b/dv/uvm/tests/core_ibex_base_test.sv index d68893af..890f2bc1 100644 --- a/dv/uvm/tests/core_ibex_base_test.sv +++ b/dv/uvm/tests/core_ibex_base_test.sv @@ -5,7 +5,7 @@ class core_ibex_base_test extends uvm_test; virtual core_ibex_dut_probe_if dut_vif; mem_model_pkg::mem_model mem; core_ibex_vseq vseq; - int unsigned timeout_in_cycles = 1000000; + int unsigned timeout_in_cycles = 2000000; `uvm_component_utils(core_ibex_base_test)