From 6d674924a8b53b052568bf832d7e4b9233c96292 Mon Sep 17 00:00:00 2001 From: Bill Moore Date: Mon, 23 Sep 2024 14:52:05 -0700 Subject: [PATCH] Create interface class for bathtub. - modified: src/bathtub_pkg/bathtub.svh - Implement new interface class, `bathtub_interface`. - Because we're implementing an interface class, methods had to become virtual. - Break include loops. - new file: src/bathtub_pkg/bathtub_interface.svh - New interface class for `bathtub`. - modified: src/bathtub_pkg/bathtub_pkg.svh - Removed `step_attributes_pool_t` typedef to its own file. - Why? I'm glad you asked. - It was responsible for a very tricky include loop. - The crux was that any file that needed something as innocuous as `strings_t` had to read this file, which meant it had to include `step_nurture.svh`, which turned out to be a six-degrees-of-separation nexus that led to a loop that could not be resolved. - The solution was to move `step_attributes_pool_t` out, with the express goal that `bathtub_pkg.svh` now does not include any other files. - Anyfile that requires a declaration in this file no longer inherits an unrelated include file with all its headaches. - modified: src/bathtub_pkg/bathtub_utils.svh - modified: src/bathtub_pkg/gherkin_document_printer/gherkin_document_printer.svh - Break an include loop. - modified: src/bathtub_pkg/gherkin_document_runner/gherkin_document_runner.svh - This is the one file that actually requies `step_attributes_pool_t`, so this file includes it directly, instead of going through `bathtub_pkg.svh`. - Break an include loop. - new file: src/bathtub_pkg/step_attributes_pool_t.svh - New file for a single typedef. - Seems extravagant, but that typedef is dependent on another include file that was causing trouble, so the "expense" of a new file that breaks an otherwise uncompilable loop is justified. - modified: test/dependency_test.py - Test the two new files. --- src/bathtub_pkg/bathtub.svh | 80 +++++++++++-------- src/bathtub_pkg/bathtub_interface.svh | 65 +++++++++++++++ src/bathtub_pkg/bathtub_pkg.svh | 4 - src/bathtub_pkg/bathtub_utils.svh | 2 + .../gherkin_document_printer.svh | 5 +- .../gherkin_document_runner.svh | 5 ++ src/bathtub_pkg/step_attributes_pool_t.svh | 35 ++++++++ test/dependency_test.py | 2 + 8 files changed, 158 insertions(+), 40 deletions(-) create mode 100644 src/bathtub_pkg/bathtub_interface.svh create mode 100644 src/bathtub_pkg/step_attributes_pool_t.svh diff --git a/src/bathtub_pkg/bathtub.svh b/src/bathtub_pkg/bathtub.svh index 470da53..5b72384 100644 --- a/src/bathtub_pkg/bathtub.svh +++ b/src/bathtub_pkg/bathtub.svh @@ -37,7 +37,14 @@ typedef class snippets; typedef class bathtub_sequence; `include "bathtub_macros.sv" + +`ifndef __BATHTUB_PKG_SVH `include "bathtub_pkg/bathtub_pkg.svh" +`endif + +`ifndef __BATHTUB_INTERFACE_SVH +`include "bathtub_pkg/bathtub_interface.svh" +`endif (* doc$markdown = "\ \ The simulation's entry point to Bathtub.\n\ @@ -111,8 +118,8 @@ typedef class bathtub_sequence; \ ```\n\ \ " *) -class bathtub extends uvm_component; - // ================================= +class bathtub extends uvm_component implements bathtub_interface; + // ========================================================== protected string feature_files[$]; protected uvm_sequencer_base sequencer; @@ -151,7 +158,7 @@ class bathtub extends uvm_component; \ " *) function new(string name="bathtub", uvm_component parent=null); - // ------------------------------- + // -------------------------------------------------------- super.new(name, parent); feature_files.delete(); @@ -318,8 +325,8 @@ class bathtub extends uvm_component; \ The plusarg options object contains values passed as `+bathtub_*` plusargs on the simulator command line.\n\ \ " *) - function plusarg_options get_plusarg_opts(); - // ------------------------------------- + virtual function plusarg_options get_plusarg_opts(); + // --------------------------------------------- return plusarg_opts; endfunction : get_plusarg_opts @@ -330,8 +337,8 @@ class bathtub extends uvm_component; \ `strings_t` is a typedef for `uvm_queue#(string)`.\n\ \ " *) - function strings_t get_feature_files(); - // -------------------------------- + virtual function strings_t get_feature_files(); + // ---------------------------------------- get_feature_files = new("feature_files"); foreach (feature_files[i]) get_feature_files.push_back(feature_files[i]); endfunction : get_feature_files @@ -353,8 +360,8 @@ class bathtub extends uvm_component; \ ```\n\ \ " *) - function void concat_feature_files(string files[$]); - // --------------------------------------------- + virtual function void concat_feature_files(string files[$]); + // ----------------------------------------------------- feature_files = {feature_files, files}; endfunction : concat_feature_files @@ -371,8 +378,8 @@ class bathtub extends uvm_component; \ ```\n\ \ " *) - function void push_back_feature_file(string file); - // ------------------------------------------- + virtual function void push_back_feature_file(string file); + // --------------------------------------------------- feature_files.push_back(file); endfunction : push_back_feature_file @@ -389,8 +396,8 @@ class bathtub extends uvm_component; \ ```\n\ \ " *) - function void set_report_object(uvm_report_object report_object); - // ---------------------------------------------------------- + virtual function void set_report_object(uvm_report_object report_object); + // ------------------------------------------------------------------ this.report_object = report_object; endfunction : set_report_object @@ -402,8 +409,8 @@ class bathtub extends uvm_component; \ Use `get_report_object()` to get the current report object.\n\ \ " *) - function uvm_report_object get_report_object(); - // ---------------------------------------- + virtual function uvm_report_object get_report_object(); + // ------------------------------------------------ return report_object; endfunction : get_report_object @@ -414,8 +421,8 @@ class bathtub extends uvm_component; \ Returns the sequencer on which Bathtub will execute all its sequences, as set by `configure()`.\n\ \ " *) - function uvm_sequencer_base get_sequencer(); - // ------------------------------------- + virtual function uvm_sequencer_base get_sequencer(); + // --------------------------------------------- return sequencer; endfunction : get_sequencer @@ -426,8 +433,8 @@ class bathtub extends uvm_component; \ Returns the sequence priority Bathtub starts all its sequences with, as set by `configure()`.\n\ \ " *) - function int get_sequence_priority(); - // ------------------------------ + virtual function int get_sequence_priority(); + // -------------------------------------- return sequence_priority; endfunction : get_sequence_priority @@ -438,8 +445,8 @@ class bathtub extends uvm_component; \ Returns the `call_pre_post` value Bathtub starts all its sequences with, as set by `configure()`.\n\ \ " *) - function bit get_sequence_call_pre_post(); - // ----------------------------------- + virtual function bit get_sequence_call_pre_post(); + // ------------------------------------------- return sequence_call_pre_post; endfunction : get_sequence_call_pre_post @@ -451,8 +458,8 @@ class bathtub extends uvm_component; \ The `get_dry_run()` function returns the dry-run status: 1=dry-run; 0=run. \n\ \ " *) - function bit get_dry_run(); - // -------------------- + virtual function bit get_dry_run(); + // ---------------------------- return dry_run; endfunction : get_dry_run @@ -465,8 +472,8 @@ class bathtub extends uvm_component; \ `get_starting_scenario_number()` returns the starting number.\n\ \ " *) - function int get_starting_scenario_number(); - // ------------------------------------- + virtual function int get_starting_scenario_number(); + // --------------------------------------------- return starting_scenario_number; endfunction : get_starting_scenario_number @@ -479,8 +486,8 @@ class bathtub extends uvm_component; \ `get_stopping_scenario_number()` returns the stopping number.\n\ \ " *) - function int get_stopping_scenario_number(); - // ------------------------------------- + virtual function int get_stopping_scenario_number(); + // --------------------------------------------- return stopping_scenario_number; endfunction : get_stopping_scenario_number @@ -493,8 +500,8 @@ class bathtub extends uvm_component; \ `get_include_tags()` returns the list of tags.\n\ \ " *) - function strings_t get_include_tags(); - // ------------------------------- + virtual function strings_t get_include_tags(); + // --------------------------------------- get_include_tags = new("include_tags"); foreach (include_tags[i]) get_include_tags.push_back(include_tags[i]); endfunction : get_include_tags @@ -508,8 +515,8 @@ class bathtub extends uvm_component; \ `get_exclude_tags()` returns the list of tags.\n\ \ " *) - function strings_t get_exclude_tags(); - // ------------------------------- + virtual function strings_t get_exclude_tags(); + // --------------------------------------- get_exclude_tags = new("exclude_tags"); foreach (exclude_tags[i]) get_exclude_tags.push_back(exclude_tags[i]); endfunction : get_exclude_tags @@ -524,8 +531,8 @@ class bathtub extends uvm_component; \ This is for internal use.\n\ \ " *) - function void concat_undefined_steps(gherkin_pkg::step steps[$]); - // ---------------------------------------------------------- + virtual function void concat_undefined_steps(gherkin_pkg::step steps[$]); + // ------------------------------------------------------------------ undefined_steps = {undefined_steps, steps}; endfunction : concat_undefined_steps @@ -570,8 +577,8 @@ class bathtub extends uvm_component; \ ```\n\ \ " *) - function uvm_sequence_base as_sequence(); - // ---------------------------------- + virtual function uvm_sequence_base as_sequence(); + // ------------------------------------------ if (bathtub_seq == null) begin bathtub_seq = bathtub_sequence::type_id::create("bathtub_seq"); bathtub_seq.configure(this); @@ -585,7 +592,10 @@ endclass : bathtub `include "bathtub_pkg/gherkin_document_printer/gherkin_document_printer.svh" `include "bathtub_pkg/plusarg_options.svh" `include "bathtub_pkg/snippets.svh" + +`ifndef __BATHTUB_SEQUENCE_SVH `include "bathtub_pkg/bathtub_sequence.svh" +`endif `ifndef __GHERKIN_DOCUMENT_RUNNER_SVH `include "bathtub_pkg/gherkin_document_runner/gherkin_document_runner.svh" diff --git a/src/bathtub_pkg/bathtub_interface.svh b/src/bathtub_pkg/bathtub_interface.svh new file mode 100644 index 0000000..3720dcd --- /dev/null +++ b/src/bathtub_pkg/bathtub_interface.svh @@ -0,0 +1,65 @@ +/* +MIT License + +Copyright (c) 2024 William L. Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +`ifndef __BATHTUB_INTERFACE_SVH +`define __BATHTUB_INTERFACE_SVH + +import uvm_pkg::*; + +`include "uvm_macros.svh" + +`include "bathtub_pkg/bathtub_pkg.svh" + +typedef class plusarg_options; + +interface class bathtub_interface; + + pure virtual function void configure( + uvm_sequencer_base sequencer, + uvm_sequence_base parent_sequence = null, + int sequence_priority = 100, + bit sequence_call_pre_post = 1 + ); + pure virtual function plusarg_options get_plusarg_opts(); + pure virtual function strings_t get_feature_files(); + pure virtual function void concat_feature_files(string files[$]); + pure virtual function void push_back_feature_file(string file); + pure virtual function void set_report_object(uvm_report_object report_object); + pure virtual function uvm_report_object get_report_object(); + pure virtual function uvm_sequencer_base get_sequencer(); + pure virtual function int get_sequence_priority(); + pure virtual function bit get_sequence_call_pre_post(); + pure virtual function bit get_dry_run(); + pure virtual function int get_starting_scenario_number(); + pure virtual function int get_stopping_scenario_number(); + pure virtual function strings_t get_include_tags(); + pure virtual function strings_t get_exclude_tags(); + pure virtual function void concat_undefined_steps(gherkin_pkg::step steps[$]); + pure virtual function uvm_sequence_base as_sequence(); + +endclass : bathtub_interface + +`include "bathtub_pkg/plusarg_options.svh" + +`endif // __BATHTUB_INTERFACE_SVH diff --git a/src/bathtub_pkg/bathtub_pkg.svh b/src/bathtub_pkg/bathtub_pkg.svh index 0afeca1..9fa121e 100644 --- a/src/bathtub_pkg/bathtub_pkg.svh +++ b/src/bathtub_pkg/bathtub_pkg.svh @@ -26,11 +26,9 @@ SOFTWARE. `define __BATHTUB_PKG_SVH import uvm_pkg::*; -typedef class step_nurture; typedef enum {Given, When, Then, And, But, \* } step_keyword_t; typedef uvm_queue#(string) strings_t; -typedef uvm_pool#(uvm_sequence_base, step_nurture) step_attributes_pool_t; parameter byte CR = 13; // ASCII carriage return parameter string STEP_DEF_RESOURCE_NAME = "bathtub_pkg::step_definition_interface"; @@ -43,6 +41,4 @@ const struct { string : "" }; -`include "bathtub_pkg/step_nurture.svh" - `endif // __BATHTUB_PKG_SVH diff --git a/src/bathtub_pkg/bathtub_utils.svh b/src/bathtub_pkg/bathtub_utils.svh index 09d6fdf..d0db7f4 100644 --- a/src/bathtub_pkg/bathtub_utils.svh +++ b/src/bathtub_pkg/bathtub_utils.svh @@ -25,7 +25,9 @@ SOFTWARE. `ifndef __BATHTUB_UTILS_SVH `define __BATHTUB_UTILS_SVH +`ifndef __BATHTUB_PKG_SVH `include "bathtub_pkg/bathtub_pkg.svh" +`endif import uvm_pkg::*; diff --git a/src/bathtub_pkg/gherkin_document_printer/gherkin_document_printer.svh b/src/bathtub_pkg/gherkin_document_printer/gherkin_document_printer.svh index 8ca65d4..110c935 100644 --- a/src/bathtub_pkg/gherkin_document_printer/gherkin_document_printer.svh +++ b/src/bathtub_pkg/gherkin_document_printer/gherkin_document_printer.svh @@ -28,9 +28,12 @@ SOFTWARE. import uvm_pkg::*; import gherkin_pkg::gherkin_pkg_metadata; -`include "bathtub_pkg/bathtub_pkg.svh" `include "uvm_macros.svh" +`ifndef __BATHTUB_PKG_SVH +`include "bathtub_pkg/bathtub_pkg.svh" +`endif + class gherkin_document_printer extends uvm_object implements gherkin_pkg::visitor; gherkin_pkg::gherkin_document document; diff --git a/src/bathtub_pkg/gherkin_document_runner/gherkin_document_runner.svh b/src/bathtub_pkg/gherkin_document_runner/gherkin_document_runner.svh index 763ae4d..cf3dc23 100644 --- a/src/bathtub_pkg/gherkin_document_runner/gherkin_document_runner.svh +++ b/src/bathtub_pkg/gherkin_document_runner/gherkin_document_runner.svh @@ -56,7 +56,10 @@ typedef class scenario_sequence; `endif // __SCENARIO_SEQUENCE_SVH typedef class step_nurture; +`ifndef __STEP_NURTURE_SVH +// Prevent `include recursion `include "bathtub_pkg/step_nurture.svh" +`endif // __STEP_NURTURE_SVH typedef interface class step_definition_interface; `include "bathtub_pkg/step_definition_interface.svh" @@ -64,6 +67,8 @@ typedef interface class step_definition_interface; typedef class bathtub_utils; `include "bathtub_pkg/bathtub_utils.svh" +`include "bathtub_pkg/step_attributes_pool_t.svh" + class gherkin_document_runner extends uvm_object implements gherkin_pkg::visitor; gherkin_pkg::gherkin_document document; diff --git a/src/bathtub_pkg/step_attributes_pool_t.svh b/src/bathtub_pkg/step_attributes_pool_t.svh new file mode 100644 index 0000000..822b2c3 --- /dev/null +++ b/src/bathtub_pkg/step_attributes_pool_t.svh @@ -0,0 +1,35 @@ +/* +MIT License + +Copyright (c) 2024 William L. Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +`ifndef __STEP_ATTRIBUTES_POOL_T_SVH +`define __STEP_ATTRIBUTES_POOL_T_SVH + +import uvm_pkg::*; +typedef class step_nurture; + +typedef uvm_pool#(uvm_sequence_base, step_nurture) step_attributes_pool_t; + +`include "bathtub_pkg/step_nurture.svh" + +`endif // __STEP_ATTRIBUTES_POOL_T_SVH diff --git a/test/dependency_test.py b/test/dependency_test.py index 29329e8..04ab357 100644 --- a/test/dependency_test.py +++ b/test/dependency_test.py @@ -24,6 +24,7 @@ classes_under_test = [ "bathtub_pkg/bathtub.svh", + "bathtub_pkg/bathtub_interface.svh", "bathtub_pkg/bathtub_pkg.svh", "bathtub_pkg/bathtub_sequence.svh", "bathtub_pkg/bathtub_utils.svh", @@ -45,6 +46,7 @@ "bathtub_pkg/scenario_sequence_interface.svh", "bathtub_pkg/snippets.svh", "bathtub_pkg/step_attributes_interface.svh", + "bathtub_pkg/step_attributes_pool_t.svh", "bathtub_pkg/step_definition_interface.svh", "bathtub_pkg/step_definition_seq.svh", "bathtub_pkg/step_nature.svh",