DMA DV framework -Generated by uvmdvgen -Implement smoke test only Change-Id: I2a355cc75080e6340deb06c3667575014e7dca39
diff --git a/hw/top_matcha/ip/dma/data/dma_testplan.hjson b/hw/top_matcha/ip/dma/data/dma_testplan.hjson index 7ba2ea0..d9610f9 100644 --- a/hw/top_matcha/ip/dma/data/dma_testplan.hjson +++ b/hw/top_matcha/ip/dma/data/dma_testplan.hjson
@@ -27,7 +27,7 @@ - Source and destination memory contain the same data. ''' - stage: V0 + stage: V1 tests: ["dma_smoke"] } { @@ -41,7 +41,7 @@ - The data written by the writer matches the data written to the reader. ''' - stage: V0 + stage: V1 tests: [] } { @@ -54,7 +54,7 @@ Check - Read from the writer and confirm it's the same data fetched by the reader. ''' - stage: V0 + stage: V1 tests: [] } { @@ -68,7 +68,7 @@ Check - Confirm the address stays fixed and valid data is fetched to the reader. ''' - stage: V0 + stage: V1 tests: [] } { @@ -82,7 +82,7 @@ Check - Confirm the address stays fixed and valid data is written by the writer. ''' - stage: V0 + stage: V1 tests: [] } ]
diff --git a/hw/top_matcha/ip/dma/dv/README.md b/hw/top_matcha/ip/dma/dv/README.md new file mode 100644 index 0000000..91b15e7 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/README.md
@@ -0,0 +1,22 @@ +**Copyright 2023 Google LLC.** + +1. Set up environment: + +In the root of the shodan repo: + +``` +export ROOTDIR=`pwd` +export titan_root=$ROOTDIR/hw/opentitan-upstream +export PYTHONPATH=$ROOTDIR/hw/matcha/util:$titan_root/util:$titan_root/util/dvsim:$PYTHONPATH +``` + +2. Sample command to run DMA tests + +``` +cd $ROOTDIR/hw/matcha +./util/dvsim_matcha/dvsim.py ./hw/top_matcha/ip/dma/dv/dma_sim_cfg.hjson -i dma_smoke +``` + +3. Run in debug mode with `-v d` option + +4. Dump out waveform with `-w fsdb` option \ No newline at end of file
diff --git a/hw/top_matcha/ip/dma/dv/dma_sim.core b/hw/top_matcha/ip/dma/dv/dma_sim.core new file mode 100644 index 0000000..c091987 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/dma_sim.core
@@ -0,0 +1,31 @@ +CAPI=2: +# Coyright 2023 Google LLC. +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dma_sim:0.1" +description: "DMA DV sim target" +filesets: + files_rtl: + depend: + - google:ip:dma + + files_dv: + depend: + - lowrisc:dv:dma_test + - lowrisc:dv:dma_sva + files: + - tb.sv + file_type: systemVerilogSource + +targets: + sim: &sim_target + toplevel: tb + filesets: + - files_rtl + - files_dv + default_tool: vcs + + # TODO: add a lint check cfg in `hw/top_earlgrey/lint/top_earlgrey_dv_lint_cfgs.hjson` + lint: + <<: *sim_target
diff --git a/hw/top_matcha/ip/dma/dv/dma_sim_cfg.hjson b/hw/top_matcha/ip/dma/dv/dma_sim_cfg.hjson new file mode 100644 index 0000000..0d3f389 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/dma_sim_cfg.hjson
@@ -0,0 +1,63 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + // Name of the sim cfg - typically same as the name of the DUT. + name: dma + + // Top level dut name (sv module). + dut: dma + + // Top level testbench name (sv module). + tb: tb + + // Simulator used to sign off this block + tool: vcs + + // Fusesoc core file used for building the file list. + fusesoc_core: lowrisc:dv:dma_sim:0.1 + + // Testplan hjson file. + testplan: "{proj_root}/hw/top_matcha/ip/dma/data/dma_testplan.hjson" + + // RAL spec - used to generate the RAL model. + ral_spec: "{proj_root}/hw/ip/dma/data/dma.hjson" + + // Import additional common sim cfg files. + // TODO: remove imported cfgs that do not apply. + import_cfgs: [// Project wide common sim cfg file + "{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson", + // Common CIP test lists + "{titan_root}/hw/dv/tools/dvsim/tests/csr_tests.hjson", + "{titan_root}/hw/dv/tools/dvsim/tests/mem_tests.hjson", + "{titan_root}/hw/dv/tools/dvsim/tests/tl_access_tests.hjson"] + + // Add additional tops for simulation. + sim_tops: ["dma_bind"] + + // Default iterations for all tests - each test entry can override this. + reseed: 1 + + // Default UVM test and seq class name. + uvm_test: dma_base_test + uvm_test_seq: dma_base_vseq + + // List of test specifications. + tests: [ + { + name: dma_smoke + uvm_test_seq: dma_smoke_vseq + } + + // TODO: add more tests here + ] + + // List of regressions. + regressions: [ + { + name: smoke + tests: ["dma_smoke"] + } + ] +}
diff --git a/hw/top_matcha/ip/dma/dv/env/dma_env.core b/hw/top_matcha/ip/dma/dv/env/dma_env.core new file mode 100644 index 0000000..e8b3f15 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/dma_env.core
@@ -0,0 +1,38 @@ +CAPI=2: +# Copyright 2023 Google LLC. +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dma_env:0.1" +description: "DMA DV UVM environment" +filesets: + files_dv: + depend: + - lowrisc:dv:ralgen_matcha + - lowrisc:dv:cip_lib + files: + - dma_env_pkg.sv + - dma_env_cfg.sv: {is_include_file: true} + - dma_env_cov.sv: {is_include_file: true} + - dma_virtual_sequencer.sv: {is_include_file: true} + - dma_scoreboard.sv: {is_include_file: true} + - dma_env.sv: {is_include_file: true} + - seq_lib/dma_vseq_list.sv: {is_include_file: true} + - seq_lib/dma_base_vseq.sv: {is_include_file: true} + - seq_lib/dma_common_vseq.sv: {is_include_file: true} + - seq_lib/dma_smoke_vseq.sv: {is_include_file: true} + file_type: systemVerilogSource + +generate: + ral: + generator: ralgen + parameters: + name: dma + ip_hjson: ../../data/dma.hjson + +targets: + default: + filesets: + - files_dv + generate: + - ral
diff --git a/hw/top_matcha/ip/dma/dv/env/dma_env.sv b/hw/top_matcha/ip/dma/dv/env/dma_env.sv new file mode 100644 index 0000000..146e5f9 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/dma_env.sv
@@ -0,0 +1,55 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class dma_env extends cip_base_env #( + .CFG_T (dma_env_cfg), + .COV_T (dma_env_cov), + .VIRTUAL_SEQUENCER_T(dma_virtual_sequencer), + .SCOREBOARD_T (dma_scoreboard) + ); + `uvm_component_utils(dma_env) + + tl_agent m_reader_tl_agent; + tl_agent m_writer_tl_agent; + + `uvm_component_new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + // create components + m_reader_tl_agent = tl_agent::type_id::create("m_reader_tl_agent", this); + uvm_config_db#(tl_agent_cfg)::set(this, "m_reader_tl_agent*", "cfg", cfg.m_reader_tl_agent_cfg); + cfg.m_reader_tl_agent_cfg.en_cov = cfg.en_cov; + // create components + m_writer_tl_agent = tl_agent::type_id::create("m_writer_tl_agent", this); + uvm_config_db#(tl_agent_cfg)::set(this, "m_writer_tl_agent*", "cfg", cfg.m_writer_tl_agent_cfg); + cfg.m_writer_tl_agent_cfg.en_cov = cfg.en_cov; + endfunction + + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + if (cfg.en_scb) begin + m_reader_tl_agent.monitor.a_chan_port.connect(scoreboard.reader_tl_a_chan_fifo.analysis_export); + m_reader_tl_agent.monitor.d_chan_port.connect(scoreboard.reader_tl_d_chan_fifo.analysis_export); + m_writer_tl_agent.monitor.a_chan_port.connect(scoreboard.writer_tl_a_chan_fifo.analysis_export); + m_writer_tl_agent.monitor.d_chan_port.connect(scoreboard.writer_tl_d_chan_fifo.analysis_export); + end + if (cfg.is_active && cfg.m_reader_tl_agent_cfg.is_active) begin + virtual_sequencer.reader_tl_sequencer_h = m_reader_tl_agent.sequencer; + end + if (cfg.is_active && cfg.m_writer_tl_agent_cfg.is_active) begin + virtual_sequencer.writer_tl_sequencer_h = m_writer_tl_agent.sequencer; + end + + // Connect the DUT's reader tl to the sequencer + m_reader_tl_agent.monitor.d_chan_port.connect( + virtual_sequencer.reader_tl_rx_fifo.analysis_export); + + // Connect the DUT's writer tl to the sequencer + m_writer_tl_agent.monitor.a_chan_port.connect( + virtual_sequencer.writer_tl_rx_fifo.analysis_export); + endfunction + +endclass
diff --git a/hw/top_matcha/ip/dma/dv/env/dma_env_cfg.sv b/hw/top_matcha/ip/dma/dv/env/dma_env_cfg.sv new file mode 100644 index 0000000..69ea0d6 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/dma_env_cfg.sv
@@ -0,0 +1,53 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class dma_env_cfg extends cip_base_env_cfg #(.RAL_T(dma_reg_block)); + + // ext component cfgs + rand tl_agent_cfg m_reader_tl_agent_cfg; + rand tl_agent_cfg m_writer_tl_agent_cfg; + + `uvm_object_utils_begin(dma_env_cfg) + `uvm_field_object(m_reader_tl_agent_cfg, UVM_DEFAULT) + `uvm_field_object(m_writer_tl_agent_cfg, UVM_DEFAULT) + `uvm_object_utils_end + + `uvm_object_new + + virtual function void initialize(bit [31:0] csr_base_addr = 32'h40200000); + super.initialize(csr_base_addr); + // create reader_tl agent config obj + m_reader_tl_agent_cfg = tl_agent_cfg::type_id::create("m_reader_tl_agent_cfg"); + m_reader_tl_agent_cfg.if_mode = dv_utils_pkg::Device; + m_reader_tl_agent_cfg.is_active = 1; + m_reader_tl_agent_cfg.device_can_rsp_on_same_cycle = 1; + m_reader_tl_agent_cfg.a_valid_delay_min = 0; + m_reader_tl_agent_cfg.a_valid_delay_max = 0; + m_reader_tl_agent_cfg.d_valid_delay_min = 0; + m_reader_tl_agent_cfg.d_valid_delay_max = 0; + m_reader_tl_agent_cfg.a_ready_delay_min = 0; + m_reader_tl_agent_cfg.a_ready_delay_max = 0; + m_reader_tl_agent_cfg.d_ready_delay_min = 0; + m_reader_tl_agent_cfg.d_ready_delay_max = 0; + + // create writer_tl agent config obj + m_writer_tl_agent_cfg = tl_agent_cfg::type_id::create("m_writer_tl_agent_cfg"); + m_writer_tl_agent_cfg.if_mode = dv_utils_pkg::Device; + m_writer_tl_agent_cfg.is_active = 1; + m_writer_tl_agent_cfg.device_can_rsp_on_same_cycle = 1; + m_writer_tl_agent_cfg.a_valid_delay_min = 0; + m_writer_tl_agent_cfg.a_valid_delay_max = 0; + m_writer_tl_agent_cfg.d_valid_delay_min = 0; + m_writer_tl_agent_cfg.d_valid_delay_max = 0; + m_writer_tl_agent_cfg.a_ready_delay_min = 0; + m_writer_tl_agent_cfg.a_ready_delay_max = 0; + m_writer_tl_agent_cfg.d_ready_delay_min = 0; + m_writer_tl_agent_cfg.d_ready_delay_max = 0; + + // only support 1 outstanding TL items in tlul_adapter + m_tl_agent_cfg.max_outstanding_req = 1; + endfunction + +endclass
diff --git a/hw/top_matcha/ip/dma/dv/env/dma_env_cov.sv b/hw/top_matcha/ip/dma/dv/env/dma_env_cov.sv new file mode 100644 index 0000000..79064da --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/dma_env_cov.sv
@@ -0,0 +1,33 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Covergoups that are dependent on run-time parameters that may be available + * only in build_phase can be defined here + * Covergroups may also be wrapped inside helper classes if needed. + */ + +class dma_env_cov extends cip_base_env_cov #(.CFG_T(dma_env_cfg)); + `uvm_component_utils(dma_env_cov) + + // the base class provides the following handles for use: + // dma_env_cfg: cfg + + // covergroups + // [add covergroups here] + + function new(string name, uvm_component parent); + super.new(name, parent); + // [instantiate covergroups here] + endfunction : new + + virtual function void build_phase(uvm_phase phase); + super.build_phase(phase); + // [or instantiate covergroups here] + // Please instantiate sticky_intr_cov array of objects for all interrupts that are sticky + // See cip_base_env_cov for details + endfunction + +endclass
diff --git a/hw/top_matcha/ip/dma/dv/env/dma_env_pkg.sv b/hw/top_matcha/ip/dma/dv/env/dma_env_pkg.sv new file mode 100644 index 0000000..fecef3c --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/dma_env_pkg.sv
@@ -0,0 +1,36 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package dma_env_pkg; + // dep packages + import uvm_pkg::*; + import top_pkg::*; + import dv_utils_pkg::*; + import dv_lib_pkg::*; + import tl_agent_pkg::*; + import cip_base_pkg::*; + import dv_base_reg_pkg::*; + import csr_utils_pkg::*; + import dma_ral_pkg::*; + + // macro includes + `include "uvm_macros.svh" + `include "dv_macros.svh" + + // parameters + + // types + + // functions + + // package sources + `include "dma_env_cfg.sv" + `include "dma_env_cov.sv" + `include "dma_virtual_sequencer.sv" + `include "dma_scoreboard.sv" + `include "dma_env.sv" + `include "dma_vseq_list.sv" + +endpackage
diff --git a/hw/top_matcha/ip/dma/dv/env/dma_scoreboard.sv b/hw/top_matcha/ip/dma/dv/env/dma_scoreboard.sv new file mode 100644 index 0000000..cb52101 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/dma_scoreboard.sv
@@ -0,0 +1,150 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class dma_scoreboard extends cip_base_scoreboard #( + .CFG_T(dma_env_cfg), + .RAL_T(dma_reg_block), + .COV_T(dma_env_cov) + ); + `uvm_component_utils(dma_scoreboard) + + // local variables + + // TLM agent fifos + uvm_tlm_analysis_fifo #(tl_seq_item) reader_tl_a_chan_fifo; + uvm_tlm_analysis_fifo #(tl_seq_item) reader_tl_d_chan_fifo; + uvm_tlm_analysis_fifo #(tl_seq_item) writer_tl_a_chan_fifo; + uvm_tlm_analysis_fifo #(tl_seq_item) writer_tl_d_chan_fifo; + + // local queues to hold incoming packets pending comparison + tl_seq_item reader_tl_q[$]; + tl_seq_item writer_tl_q[$]; + + `uvm_component_new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + reader_tl_a_chan_fifo = new("reader_tl_a_chan_fifo", this); + reader_tl_d_chan_fifo = new("reader_tl_d_chan_fifo", this); + writer_tl_a_chan_fifo = new("writer_tl_a_chan_fifo", this); + writer_tl_d_chan_fifo = new("writer_tl_d_chan_fifo", this); + endfunction + + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + endfunction + + task run_phase(uvm_phase phase); + super.run_phase(phase); + fork + process_reader_tl_a_chan_fifo(); + process_reader_tl_d_chan_fifo(); + + process_writer_tl_a_chan_fifo(); + process_writer_tl_d_chan_fifo(); + join_none + endtask + + virtual task process_reader_tl_a_chan_fifo(); + tl_seq_item item; + forever begin + reader_tl_a_chan_fifo.get(item); + `uvm_info(`gfn, $sformatf("received reader_tl a_chan item:\n%0s", item.sprint()), UVM_HIGH) + end + endtask + + virtual task process_reader_tl_d_chan_fifo(); + tl_seq_item item; + forever begin + reader_tl_d_chan_fifo.get(item); + `uvm_info(`gfn, $sformatf("received reader_tl d_chan item:\n%0s", item.sprint()), UVM_HIGH) + end + endtask + + virtual task process_writer_tl_a_chan_fifo(); + tl_seq_item item; + forever begin + writer_tl_a_chan_fifo.get(item); + `uvm_info(`gfn, $sformatf("received writer_tl a_chan_item:\n%0s", item.sprint()), UVM_HIGH) + end + endtask + + virtual task process_writer_tl_d_chan_fifo(); + tl_seq_item item; + forever begin + writer_tl_d_chan_fifo.get(item); + `uvm_info(`gfn, $sformatf("received writer_tl d_chan_item:\n%0s", item.sprint()), UVM_HIGH) + end + endtask + + virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name); + uvm_reg csr; + bit do_read_check = 1'b1; + bit write = item.is_write(); + uvm_reg_addr_t csr_addr = cfg.ral_models[ral_name].get_word_aligned_addr(item.a_addr); + + bit addr_phase_read = (!write && channel == AddrChannel); + bit addr_phase_write = (write && channel == AddrChannel); + bit data_phase_read = (!write && channel == DataChannel); + bit data_phase_write = (write && channel == DataChannel); + + // if access was to a valid csr, get the csr handle + if (csr_addr inside {cfg.ral_models[ral_name].csr_addrs}) begin + csr = cfg.ral_models[ral_name].default_map.get_reg_by_offset(csr_addr); + `DV_CHECK_NE_FATAL(csr, null) + end + else begin + `uvm_fatal(`gfn, $sformatf("Access unexpected addr 0x%0h", csr_addr)) + end + + // if incoming access is a write to a valid csr, then make updates right away + if (addr_phase_write) begin + void'(csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask))); + end + + // process the csr req + // for write, update local variable and fifo at address phase + // for read, update predication at address phase and compare at data phase + case (csr.get_name()) + "ctrl", + "status", + "rdr_start_addr", + "rdr_length", + "rdr_line_cnt", + "rdr_stride", + "wtr_start_addr", + "wtr_length", + "wtr_line_cnt", + "wtr_stride", + "intr_state", + "intr_enable": + begin + end + default: begin + `uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name())) + end + endcase + + // On reads, if do_read_check, is set, then check mirrored_value against item.d_data + if (data_phase_read) begin + if (do_read_check) begin + `DV_CHECK_EQ(csr.get_mirrored_value(), item.d_data, + $sformatf("reg name: %0s", csr.get_full_name())) + end + void'(csr.predict(.value(item.d_data), .kind(UVM_PREDICT_READ))); + end + endtask + + virtual function void reset(string kind = "HARD"); + super.reset(kind); + // reset local fifos queues and variables + endfunction + + function void check_phase(uvm_phase phase); + super.check_phase(phase); + // post test checks - ensure that all local fifos and queues are empty + endfunction + +endclass
diff --git a/hw/top_matcha/ip/dma/dv/env/dma_virtual_sequencer.sv b/hw/top_matcha/ip/dma/dv/env/dma_virtual_sequencer.sv new file mode 100644 index 0000000..aedfad6 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/dma_virtual_sequencer.sv
@@ -0,0 +1,29 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class dma_virtual_sequencer extends cip_base_virtual_sequencer #( + .CFG_T(dma_env_cfg), + .COV_T(dma_env_cov) + ); + `uvm_component_utils(dma_virtual_sequencer) + + tl_sequencer reader_tl_sequencer_h; + tl_sequencer writer_tl_sequencer_h; + + // Grab packets from reader_tl_if + uvm_tlm_analysis_fifo #(tl_seq_item) reader_tl_rx_fifo; + + // Grab packets from writer_tl_if + uvm_tlm_analysis_fifo #(tl_seq_item) writer_tl_rx_fifo; + + `uvm_component_new + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + reader_tl_rx_fifo = new("reader_tl_rx_fifo", this); + writer_tl_rx_fifo = new("writer_tl_rx_fifo", this); + endfunction + +endclass
diff --git a/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_base_vseq.sv b/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_base_vseq.sv new file mode 100644 index 0000000..54cd1ed --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_base_vseq.sv
@@ -0,0 +1,75 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class dma_base_vseq extends cip_base_vseq #( + .RAL_T (dma_reg_block), + .CFG_T (dma_env_cfg), + .COV_T (dma_env_cov), + .VIRTUAL_SEQUENCER_T (dma_virtual_sequencer) + ); + `uvm_object_utils(dma_base_vseq) + + // various knobs to enable certain routines + bit do_dma_init = 1'b1; + + // Local queue for holding received writer data + byte writer_data_q[$]; + + `uvm_object_new + + // Grab packets sent by the DUT over the writer tl + virtual task get_writer_data_items(); + tl_seq_item item; + + forever begin + p_sequencer.writer_tl_rx_fifo.get(item); + `uvm_info(`gfn, $sformatf("Received data from DMA:\n%0h", item.a_data), UVM_HIGH) + writer_data_q.push_back(item.a_data & 32'h000000FF); + end + endtask + + virtual task dut_init(string reset_kind = "HARD"); + super.dut_init(); + if (do_dma_init) dma_init(); + endtask + + virtual task dut_shutdown(); + // check for pending dma operations and wait for them to complete + // TODO + endtask + + // setup basic dma features + virtual task dma_init(); + endtask + + virtual task dma_setup(int read_addr, int write_addr, int line_width, int line_count, int line_stride); + ral.rdr_start_addr.set(read_addr); + csr_update(.csr(ral.rdr_start_addr)); + ral.rdr_length.set(line_width); + csr_update(.csr(ral.rdr_length)); + ral.rdr_line_cnt.set(line_count); + csr_update(.csr(ral.rdr_line_cnt)); + ral.rdr_stride.set(line_stride); + csr_update(.csr(ral.rdr_stride)); + + ral.wtr_start_addr.set(write_addr); + csr_update(.csr(ral.wtr_start_addr)); + ral.wtr_length.set(line_width); + csr_update(.csr(ral.wtr_length)); + ral.wtr_line_cnt.set(line_count); + csr_update(.csr(ral.wtr_line_cnt)); + ral.wtr_stride.set(line_stride); + csr_update(.csr(ral.wtr_stride)); + endtask + + virtual task dma_start(); + ral.ctrl.rdr_start.set(1'b1); + ral.ctrl.wtr_start.set(1'b1); + ral.ctrl.rdr_sync_dis.set(1'b1); + ral.ctrl.wtr_sync_dis.set(1'b1); + csr_update(.csr(ral.ctrl)); + endtask + +endclass : dma_base_vseq
diff --git a/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_common_vseq.sv b/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_common_vseq.sv new file mode 100644 index 0000000..294f5ec --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_common_vseq.sv
@@ -0,0 +1,18 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class dma_common_vseq extends dma_base_vseq; + `uvm_object_utils(dma_common_vseq) + + constraint num_trans_c { + num_trans inside {[1:2]}; + } + `uvm_object_new + + virtual task body(); + run_common_vseq_wrapper(num_trans); + endtask : body + +endclass
diff --git a/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_smoke_vseq.sv b/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_smoke_vseq.sv new file mode 100644 index 0000000..fa43ae7 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_smoke_vseq.sv
@@ -0,0 +1,74 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// smoke test vseq +class dma_smoke_vseq extends dma_base_vseq; + `uvm_object_utils(dma_smoke_vseq) + + `uvm_object_new + + localparam uint DMA_READ_ADDR = 32'h10008000; + localparam uint DMA_WRITE_ADDR = 32'h50020000; + localparam uint DMA_LINE_WIDTH = 1; + localparam uint DMA_DATA_SIZE = 1; + localparam uint DMA_LINE_STRIDE = 0; + + tl_device_seq reader_device_seq; + tl_device_seq writer_device_seq; + + // A set of bytes expected to be received on writer tl + byte exp_writer_data_q[$]; + + task process_reader_request(); + tl_seq_item item; + + forever begin + p_sequencer.reader_tl_rx_fifo.get(item); + + `uvm_info(`gfn, $sformatf("Sending data from reader_tl:\n%0h", item.d_data), UVM_HIGH) + exp_writer_data_q.push_back(item.d_data & 32'h000000FF); + end + endtask + + task start_reader_device_seq(); + // Create and start tl_device_seq on reader_tl + reader_device_seq = tl_device_seq#()::type_id::create("reader_device_seq"); + reader_device_seq.start(p_sequencer.reader_tl_sequencer_h); + + endtask + + task start_writer_device_seq(); + // Create and start tl_device_seq on writer_tl + writer_device_seq = tl_device_seq#()::type_id::create("writer_device_seq"); + writer_device_seq.start(p_sequencer.writer_tl_sequencer_h); + endtask + + virtual task body(); + // super.body(); + + fork start_reader_device_seq(); join_none + fork start_writer_device_seq(); join_none + + #1000 + `uvm_info(`gfn, "Configuring DMA", UVM_HIGH) + dma_setup(DMA_READ_ADDR, DMA_WRITE_ADDR, DMA_LINE_WIDTH, DMA_DATA_SIZE, DMA_LINE_STRIDE); + + #1000 + `uvm_info(`gfn, "Starting DMA", UVM_HIGH) + dma_start(); + + // Spawn off a thread to handle reader tl + fork process_reader_request(); join_none + + // Spawn off a thread to handle writer tl + fork get_writer_data_items(); join_none + + #100000 + foreach (exp_writer_data_q[i]) begin + `DV_CHECK_EQ(writer_data_q[i], exp_writer_data_q[i], $sformatf("index: %0d", i)) + end + endtask : body + +endclass : dma_smoke_vseq
diff --git a/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_vseq_list.sv b/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_vseq_list.sv new file mode 100644 index 0000000..5f58bf0 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/env/seq_lib/dma_vseq_list.sv
@@ -0,0 +1,8 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "dma_base_vseq.sv" +`include "dma_smoke_vseq.sv" +`include "dma_common_vseq.sv"
diff --git a/hw/top_matcha/ip/dma/dv/sva/dma_bind.sv b/hw/top_matcha/ip/dma/dv/sva/dma_bind.sv new file mode 100644 index 0000000..6365454 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/sva/dma_bind.sv
@@ -0,0 +1,24 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +module dma_bind; + + bind dma tlul_assert #( + .EndpointType("Device") + ) tlul_assert_device ( + .clk_i, + .rst_ni, + .h2d (tl_d_i), + .d2h (tl_d_o) + ); + + bind dma dma_csr_assert_fpv dma_csr_assert ( + .clk_i, + .rst_ni, + .h2d (tl_d_i), + .d2h (tl_d_o) + ); + +endmodule
diff --git a/hw/top_matcha/ip/dma/dv/sva/dma_sva.core b/hw/top_matcha/ip/dma/dv/sva/dma_sva.core new file mode 100644 index 0000000..ae06a4f --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/sva/dma_sva.core
@@ -0,0 +1,38 @@ +CAPI=2: +# Copyright 2023 Google LLC. +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dma_sva:0.1" +description: "DMA assertion modules and bind file." +filesets: + files_dv: + depend: + - lowrisc:tlul:headers + - lowrisc:fpv:csr_assert_gen + files: + - dma_bind.sv + file_type: systemVerilogSource + + files_formal: + depend: + - lowrisc:ip:dma + +generate: + csr_assert_gen: + generator: csr_assert_gen + parameters: + spec: ../../data/dma.hjson + +targets: + default: &default_target + filesets: + - files_dv + generate: + - csr_assert_gen + formal: + <<: *default_target + filesets: + - files_formal + - files_dv + toplevel: dma
diff --git a/hw/top_matcha/ip/dma/dv/tb.sv b/hw/top_matcha/ip/dma/dv/tb.sv new file mode 100644 index 0000000..5b870e4 --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/tb.sv
@@ -0,0 +1,65 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +module tb; + // dep packages + import uvm_pkg::*; + import dv_utils_pkg::*; + import dma_env_pkg::*; + import dma_test_pkg::*; + + // macro includes + `include "uvm_macros.svh" + `include "dv_macros.svh" + + wire clk, rst_n; + wire devmode; + + // interfaces + clk_rst_if clk_rst_if(.clk(clk), .rst_n(rst_n)); + pins_if #(1) devmode_if(devmode); + tl_if tl_if(.clk(clk), .rst_n(rst_n)); + tl_if reader_tl_if(.clk(clk), .rst_n(rst_n)); + tl_if writer_tl_if(.clk(clk), .rst_n(rst_n)); + + logic intr_reader_done; + logic intr_writer_done; + + // dut + dma dut ( + .clk_i (clk ), + .rst_ni (rst_n ), + + .reader_tl_h_o (reader_tl_if.h2d), + .reader_tl_h_i (reader_tl_if.d2h), + + .writer_tl_h_o (writer_tl_if.h2d), + .writer_tl_h_i (writer_tl_if.d2h), + + .tl_d_i (tl_if.h2d), + .tl_d_o (tl_if.d2h), + + .intr_reader_done_o (intr_reader_done), + .intr_writer_done_o (intr_writer_done) + ); + + initial begin + // drive clk and rst_n from clk_if + clk_rst_if.set_active(); + uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "clk_rst_vif", clk_rst_if); + uvm_config_db#(devmode_vif)::set(null, "*.env", "devmode_vif", devmode_if); + uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if); + uvm_config_db#(virtual tl_if)::set(null, "*.env.m_reader_tl_agent*", "vif", reader_tl_if); + uvm_config_db#(virtual tl_if)::set(null, "*.env.m_writer_tl_agent*", "vif", writer_tl_if); + $timeformat(-12, 0, " ps", 12); + run_test(); + end + + initial + begin + $assertoff(0, tb.dut); + end + +endmodule
diff --git a/hw/top_matcha/ip/dma/dv/tests/dma_base_test.sv b/hw/top_matcha/ip/dma/dv/tests/dma_base_test.sv new file mode 100644 index 0000000..90d1f6c --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/tests/dma_base_test.sv
@@ -0,0 +1,27 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +class dma_base_test extends cip_base_test #( + .CFG_T(dma_env_cfg), + .ENV_T(dma_env) + ); + + `uvm_component_utils(dma_base_test) + `uvm_component_new + + // the base class dv_base_test creates the following instances: + // dma_env_cfg: cfg + // dma_env: env + + // the base class also looks up UVM_TEST_SEQ plusarg to create and run that seq in + // the run_phase; as such, nothing more needs to be done + + virtual function void build_phase(uvm_phase phase); + max_quit_count = 50; + test_timeout_ns = 600_000_000; // 600ms + super.build_phase(phase); + endfunction : build_phase + +endclass : dma_base_test
diff --git a/hw/top_matcha/ip/dma/dv/tests/dma_test.core b/hw/top_matcha/ip/dma/dv/tests/dma_test.core new file mode 100644 index 0000000..309bb5d --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/tests/dma_test.core
@@ -0,0 +1,20 @@ +CAPI=2: +# Copyright 2023 Google LLC. +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:dma_test:0.1" +description: "DMA DV UVM test" +filesets: + files_dv: + depend: + - lowrisc:dv:dma_env + files: + - dma_test_pkg.sv + - dma_base_test.sv: {is_include_file: true} + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_dv
diff --git a/hw/top_matcha/ip/dma/dv/tests/dma_test_pkg.sv b/hw/top_matcha/ip/dma/dv/tests/dma_test_pkg.sv new file mode 100644 index 0000000..f4e0f2d --- /dev/null +++ b/hw/top_matcha/ip/dma/dv/tests/dma_test_pkg.sv
@@ -0,0 +1,23 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package dma_test_pkg; + // dep packages + import uvm_pkg::*; + import cip_base_pkg::*; + import dma_env_pkg::*; + + // macro includes + `include "uvm_macros.svh" + `include "dv_macros.svh" + + // local types + + // functions + + // package sources + `include "dma_base_test.sv" + +endpackage