.
675 |
--------------------------------------------------------------------------------
/COPYRIGHT.LESSER:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | UVM Clock and Reset Agent
2 | This repository contains an implementation of a Clock agent, which is used for testbench clock generation, written in UVM 1.1d and SystemVerilog-2012.
3 | Also, a complete user guide with the agent description, instructions and usage, is provided (TBD).
The main features of the Clock agent are:
4 |
5 | - generating up to 32 unique clock sources
6 | - run-time changing of each clock phase and period
7 | - starting/stoping individual clock sources
8 | - changing each clocks polarity value
9 |
10 |
--------------------------------------------------------------------------------
/src/agent/clk_agent.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : The agent is used to control user specified clocks and resets.
6 | */
7 |
8 | class ClkAgent extends uvm_agent;
9 | `uvm_component_param_utils(ClkAgent)
10 |
11 | // Components
12 | uvm_sequencer #(ClkItem) sqcr;
13 | ClkDriver drv;
14 |
15 | // Configurations
16 | ClkAgentCfg cfg;
17 |
18 | // Ports
19 | uvm_analysis_port #(ClkItem) aport;
20 |
21 | // Constructor
22 | function new(string name = "ClkAgent", uvm_component parent = null);
23 | super.new(name, parent);
24 | endfunction
25 |
26 | // Function/Task declarations
27 | extern virtual function void build_phase (uvm_phase phase);
28 | extern virtual function void connect_phase(uvm_phase phase);
29 |
30 | endclass: ClkAgent
31 |
32 | //******************************************************************************
33 | // Function/Task implementations
34 | //******************************************************************************
35 |
36 | function void ClkAgent::build_phase(uvm_phase phase);
37 | aport = new("aport", this);
38 |
39 | // get the Clk agent configuration
40 | if (!uvm_config_db #(ClkAgentCfg)::get(this, "", "clk_agent_cfg_db", cfg)) begin
41 | `uvm_fatal("CLK_RST_AGT", "Couldn't get the Clk agent configuration")
42 | end
43 |
44 | // check if the virtual interface reference is populated
45 | if (cfg.vif == null) begin
46 | `uvm_fatal("CLK_RST_AGT", "Virtual interface not found")
47 | end
48 |
49 | // create agent components
50 | sqcr = uvm_sequencer #(ClkItem)::type_id::create("sequencer", this);
51 | drv = ClkDriver ::type_id::create( "driver", this);
52 | drv.vif = cfg.vif;
53 | endfunction: build_phase
54 |
55 | //----------------------------------------------------------------------------
56 |
57 | function void ClkAgent::connect_phase(uvm_phase phase);
58 | drv.seq_item_port.connect(sqcr.seq_item_export);
59 | endfunction: connect_phase
60 |
61 |
--------------------------------------------------------------------------------
/src/agent/clk_agent_cfg.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent configuration class. An object of this class should
6 | * be put in the configuration database so that the Clk agent can
7 | * get the user configuration.
8 | */
9 |
10 | class ClkAgentCfg extends uvm_object;
11 | `uvm_object_utils(ClkAgentCfg)
12 |
13 | // Variables
14 | virtual ClkIf vif;
15 |
16 | // Constructor
17 | function new(string name = "ClkAgentCfg");
18 | super.new(name);
19 | endfunction
20 |
21 | endclass: ClkAgentCfg
22 |
--------------------------------------------------------------------------------
/src/agent/clk_driver.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent driver. Used for generating user defined clocks.
6 | */
7 |
8 | class ClkDriver extends uvm_driver #(ClkItem);
9 | `uvm_component_utils(ClkDriver)
10 |
11 | // Components
12 | virtual ClkIf vif;
13 |
14 | // Variables
15 | protected process proc_start_clk []; // each process corresponds to one clock
16 |
17 | // Methods
18 | function new(string name = "ClkDriver", uvm_component parent);
19 | super.new(name, parent);
20 | endfunction
21 |
22 | extern virtual function void setClkPol(input ClkItem it);
23 | extern virtual function void stopClk (input ClkItem it);
24 |
25 | extern virtual task driveInit();
26 | extern virtual task setRstPol(input ClkItem it);
27 | extern virtual task waitClk (input ClkItem it);
28 | extern virtual task startClk (input ClkItem it);
29 | extern virtual task run_phase(uvm_phase phase);
30 |
31 | endclass: ClkDriver
32 |
33 | //******************************************************************************
34 | // Function/Task implementations
35 | //******************************************************************************
36 |
37 | task ClkDriver::driveInit();
38 | vif.clk = clk_init;
39 | vif.rst = rst_init;
40 | endtask: driveInit
41 |
42 | //----------------------------------------------------------------------------
43 |
44 | task ClkDriver::setRstPol(input ClkItem it);
45 | logic [31:0] clk_name;
46 |
47 | foreach (it.rst_name[i]) begin
48 | fork
49 | begin
50 | // check if the specified clock process is running
51 | if (proc_start_clk[it.clk_name[i]] == null) begin
52 | `uvm_warning("CLK_RST_DRV", $sformatf({"\nChanging %s reset polarity ignored. ",
53 | "Clock %s is not running."}, it.rst_name[i].name(), it.clk_name[i].name()))
54 | end else begin
55 | logic rst_val;
56 | logic [31:0] rst_name;
57 |
58 | rst_val = it.init[i];
59 | rst_name = it.rst_name[i];
60 | clk_name = it.clk_name[i];
61 |
62 | @(posedge vif.clk[clk_name]);
63 | #1step;
64 | vif.rst[rst_name] = rst_val;
65 | end
66 | end
67 | join_none
68 |
69 | // must use context switch because of fork-join_none
70 | #0;
71 | end
72 |
73 | // block
74 | if (it.is_blocking) begin
75 | foreach (it.clk_name[i]) begin
76 | fork
77 | begin
78 | if (proc_start_clk[it.clk_name[i]] != null) begin
79 | @(posedge vif.clk[it.clk_name[i]]);
80 | end
81 | end
82 | join
83 | end
84 | end
85 | endtask: setRstPol
86 |
87 | //----------------------------------------------------------------------------
88 |
89 | task ClkDriver::waitClk(input ClkItem it);
90 | if (proc_start_clk[it.clk_name[0]] != null) begin
91 | repeat(it.num) begin
92 | @(posedge vif.clk[it.clk_name[0]]);
93 | end
94 | end else begin
95 | `uvm_warning("CLK_RST_DRV", $sformatf("\nWaiting cycles on %s clock ignored. Clock is not running.", it.clk_name[0].name()))
96 | end
97 | endtask: waitClk
98 |
99 | //----------------------------------------------------------------------------
100 |
101 | function void ClkDriver::setClkPol(input ClkItem it);
102 | foreach (it.clk_name[i]) begin
103 | // check if an affected process is already running
104 | if (proc_start_clk[it.clk_name[i]] != null) begin
105 | `uvm_warning("CLK_RST_DRV", $sformatf("\nChanging %s clock polarity ignored. Clock is running.", it.clk_name[i].name()))
106 | end else begin
107 | vif.clk[it.clk_name[i]] = it.init[i];
108 | end
109 | end
110 | endfunction: setClkPol
111 |
112 | //----------------------------------------------------------------------------
113 |
114 | task ClkDriver::startClk(input ClkItem it);
115 | foreach (it.clk_name[i]) begin
116 | // check if an affected process is already running
117 | if (proc_start_clk[i] != null) begin
118 | proc_start_clk[i].kill();
119 | end
120 |
121 | fork
122 | begin
123 | logic init_clk_val;
124 | logic [31:0] clk_name;
125 | logic [31:0] phase_shift;
126 | logic [31:0] half_period;
127 |
128 | init_clk_val = it.init[i];
129 | clk_name = it.clk_name[i];
130 | phase_shift = it.phase_shift[i];
131 | half_period = it.period[i]/2;
132 |
133 | // start clock generation
134 | if (phase_shift) begin
135 | #phase_shift;
136 | end
137 |
138 | vif.clk[clk_name] = init_clk_val;
139 | proc_start_clk[clk_name] = process::self();
140 | forever begin
141 | vif.clk[clk_name] = #half_period ~vif.clk[clk_name];
142 | end
143 | end
144 | join_none
145 |
146 | // must use context switch because of fork-join_none
147 | #0;
148 | end
149 | endtask: startClk
150 |
151 | //----------------------------------------------------------------------------
152 |
153 | function void ClkDriver::stopClk(input ClkItem it);
154 | foreach (it.clk_name[i]) begin
155 | // check if an affected process is already running
156 | if (proc_start_clk[it.clk_name[i]] != null) begin
157 | proc_start_clk[it.clk_name[i]].kill();
158 | proc_start_clk[it.clk_name[i]] = null;
159 | end
160 | end
161 | endfunction: stopClk
162 |
163 | //----------------------------------------------------------------------------
164 |
165 | task ClkDriver::run_phase(uvm_phase phase);
166 | ClkItem it;
167 |
168 |
169 | proc_start_clk = new [C_WIDTH];
170 | driveInit();
171 | forever begin
172 | seq_item_port.get_next_item(it);
173 |
174 | case(it.op_type)
175 | RST_SET : setRstPol(it);
176 | CLK_SET : setClkPol(it);
177 | CLK_WAIT : waitClk (it);
178 | CLK_START : startClk (it);
179 | CLK_STOP : stopClk (it);
180 | default : `uvm_error("CLK_RST_DRV", "No such operation")
181 | endcase
182 |
183 | seq_item_port.item_done();
184 | end
185 | endtask: run_phase
186 |
--------------------------------------------------------------------------------
/src/clk_agent_pkg.sv:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent package. Contains :
6 | * - User specified clocks
7 | * - User specified initial clock signal values
8 | * - All needed files for building the clock and reset agent (except the interface)
9 | * - Convenience functions/tasks for clock and reset generation/stopping
10 | */
11 |
12 | `ifndef _AGENT_CLK_RST_PKG_
13 | `define _AGENT_CLK_RST_PKG_
14 |
15 | package ClkAgentPkg;
16 |
17 | timeunit 1ns;
18 | timeprecision 100ps;
19 |
20 | //==============================================================================
21 | // System section
22 | //==============================================================================
23 |
24 | //******************************************************************************
25 | // Constants, classes, types, etc.
26 | //******************************************************************************
27 |
28 | typedef enum {
29 | RST_SET,
30 | CLK_WAIT,
31 | CLK_SET,
32 | CLK_START,
33 | CLK_STOP
34 | } op_type_t;
35 |
36 | //******************************************************************************
37 | // Imports
38 | //******************************************************************************
39 |
40 | import uvm_pkg::*;
41 | import ClkAgentUserPkg::*; // user settings
42 |
43 | //******************************************************************************
44 | // Includes
45 | //******************************************************************************
46 |
47 | `include "uvm_macros.svh"
48 |
49 | // sequences
50 | `include "sequences/clk_item.svh"
51 | `include "sequences/clk_base_sequence.svh"
52 | `include "sequences/clk_start_sequence.svh"
53 | `include "sequences/clk_stop_sequence.svh"
54 | `include "sequences/clk_set_polarity_sequence.svh"
55 | `include "sequences/rst_set_polarity_sequence.svh"
56 | `include "sequences/clk_wait_cycles_sequence.svh"
57 |
58 | // components
59 | `include "agent/clk_agent_cfg.svh"
60 | `include "agent/clk_driver.svh"
61 | `include "agent/clk_agent.svh"
62 |
63 | //******************************************************************************
64 | // Functions/Tasks
65 | //******************************************************************************
66 |
67 | class PrintEnum #(type T = clk_list_t);
68 | static function automatic string printPinEnum(T a [], bit is_val);
69 | parameter DIGITS = "9876543210";
70 | string str = "";
71 | int tmp;
72 |
73 | tmp = a.size();
74 | foreach(a[i]) begin
75 | if (!is_val) begin
76 | if (i != tmp-1) begin
77 | str = {str, a[i].name(), ", "};
78 | end else begin
79 | str = {str, a[i].name()};
80 | end
81 | end else begin
82 | if (i != tmp-1) begin
83 | str = {str, DIGITS[a[i]*8+:8], ", "};
84 | end else begin
85 | str = {str, DIGITS[a[i]*8+:8]};
86 | end
87 | end
88 | end
89 | return str;
90 | endfunction : printPinEnum
91 | endclass : PrintEnum
92 |
93 | //----------------------------------------------------------------------------
94 |
95 | function automatic string printPinVal(logic v []);
96 | string str = "";
97 | string val;
98 | int tmp;
99 |
100 | tmp = v.size();
101 | foreach(v[i]) begin
102 | val = (v[i] === 1'bX) ? "X" :
103 | (v[i] === 1'bZ) ? "Z" :
104 | (v[i] === 1'b1) ? "1" : "0";
105 | if (i != tmp-1) begin
106 | str = {str, "1'b", val, ", "};
107 | end else begin
108 | str = {str, "1'b", val};
109 | end
110 | end
111 | return str;
112 | endfunction : printPinVal
113 |
114 | //----------------------------------------------------------------------------
115 |
116 | task automatic startClk(
117 | input bit _print_info = 1'b1,
118 | input uvm_sequencer_base _sqcr ,
119 | input clk_list_t _clk_name [] ,
120 | input logic _init [] = {} ,
121 | input time _period [] ,
122 | input time _phase_shift [] = {}
123 | );
124 |
125 | ClkStartSequence _seq;
126 |
127 | if (_sqcr == null) begin
128 | `uvm_error("CLK_RST_PKG", "\nClk agent sequencer handle is NULL\n")
129 | return;
130 | end
131 |
132 | if (_clk_name.size() > C_WIDTH || _clk_name.size() < 1) begin
133 | `uvm_error("CLK_RST_PKG", {"\nOperation ignored.\nNumber of specified clocks ",
134 | "is greater than number of actual clocks, or is less than one\n"})
135 | return;
136 | end
137 |
138 | if (_period.size() != _clk_name.size()) begin
139 | `uvm_error("CLK_RST_PKG", "\nNumber of specified clock periods differs from the number of clock sources.\n")
140 | return;
141 | end
142 |
143 | foreach (_period[i]) begin
144 | if (_period[i][0]) begin
145 | `uvm_warning("CLK_RST_PKG", $sformatf("\nPeriod for %s clock is not an even number\n", _clk_name[i].name()))
146 | end
147 | end
148 |
149 | _seq = ClkStartSequence::type_id::create("clk_start_seq");
150 |
151 | // set default values for initial and phase delay parameters
152 | if (!_init.size()) begin
153 | _init = new [_clk_name.size()];
154 | foreach (_init[i]) begin
155 | _init[i] = 1'b0;
156 | end
157 | end
158 |
159 | if (!_phase_shift.size()) begin
160 | _phase_shift = new [_clk_name.size()];
161 | foreach (_phase_shift[i]) begin
162 | _phase_shift[i] = 1'b0;
163 | end
164 | end
165 |
166 | if (!(_seq.randomize() with {
167 | clk_name.size() == _clk_name.size();
168 | foreach(_clk_name[i])
169 | clk_name[i] == _clk_name[i];
170 | init.size() == _init.size();
171 | foreach(_init[i])
172 | init[i] == _init[i];
173 | period.size() == _period.size();
174 | foreach(_period[i])
175 | period[i] == _period[i];
176 | phase_shift.size() == _phase_shift.size();
177 | foreach(_phase_shift[i])
178 | phase_shift[i] == _phase_shift[i];
179 | })) `uvm_error("CLK_RST_PKG", "\nRandomization failed\n")
180 |
181 | if (_print_info) begin
182 | `uvm_info("CLK_RST_PKG", $sformatf({"\nStart Clock OP:\n",
183 | "-------------------------------------------------\n",
184 | "OP Type : CLK_START\n",
185 | "Clock Name(s) : %s\n",
186 | "Clock Num(s) : %s\n",
187 | "Init. Value(s) : %s\n",
188 | "Clock Period(s) : %0t\n",
189 | "Phase Delay(s) : %0t\n"}
190 | , PrintEnum #(clk_list_t)::printPinEnum(_clk_name, 0)
191 | , PrintEnum #(clk_list_t)::printPinEnum(_clk_name, 1)
192 | , printPinVal(_init), _period, _phase_shift
193 | ), UVM_LOW)
194 | end
195 |
196 | _seq.start(_sqcr);
197 |
198 | endtask : startClk
199 |
200 | //----------------------------------------------------------------------------
201 |
202 | task automatic stopClk(
203 | input bit _print_info = 1'b1,
204 | input uvm_sequencer_base _sqcr ,
205 | input clk_list_t _clk_name []
206 | );
207 |
208 | ClkStopSequence _seq;
209 |
210 | if (_sqcr == null) begin
211 | `uvm_error("CLK_RST_PKG", "\nClk agent sequencer handle is NULL\n")
212 | return;
213 | end
214 |
215 | if (_clk_name.size() > C_WIDTH || _clk_name.size() < 1) begin
216 | `uvm_error("CLK_RST_PKG", {"\nOperation ignored.\nNumber of specified clocks ",
217 | "is greater than number of actual clocks, or is less than one\n"})
218 | return;
219 | end
220 |
221 | _seq = ClkStopSequence::type_id::create("clk_stop_seq");
222 |
223 | if (!(_seq.randomize() with {
224 | clk_name.size() == _clk_name.size();
225 | foreach(_clk_name[i])
226 | clk_name[i] == _clk_name[i];
227 | })) `uvm_error("CLK_RST_PKG", "\nRandomization failed\n");
228 |
229 | if (_print_info) begin
230 | `uvm_info("CLK_RST_PKG", $sformatf({"\nStop Clock OP:\n",
231 | "-------------------------------------------------\n",
232 | "OP Type : CLK_STOP\n",
233 | "Clock Name(s) : %s\n",
234 | "Clock Num(s) : %s\n"}
235 | , PrintEnum #(clk_list_t)::printPinEnum(_clk_name, 0)
236 | , PrintEnum #(clk_list_t)::printPinEnum(_clk_name, 1)
237 | ), UVM_LOW);
238 | end
239 |
240 | _seq.start(_sqcr);
241 |
242 | endtask : stopClk
243 |
244 | //----------------------------------------------------------------------------
245 |
246 | task automatic setClkPol(
247 | input bit _print_info = 1'b1,
248 | input uvm_sequencer_base _sqcr ,
249 | input clk_list_t _clk_name [] ,
250 | input logic _pol [] = {}
251 | );
252 |
253 | ClkSetPolaritySequence _seq;
254 |
255 | if (_sqcr == null) begin
256 | `uvm_error("CLK_RST_PKG", "\nClk agent sequencer handle is NULL\n")
257 | return;
258 | end
259 |
260 | if (_clk_name.size() > C_WIDTH || _clk_name.size() < 1) begin
261 | `uvm_error("CLK_RST_PKG", {"\nOperation ignored.\nNumber of specified clocks ",
262 | "is greater than number of actual clocks, or is less than one\n"})
263 | return;
264 | end
265 |
266 | _seq = ClkSetPolaritySequence::type_id::create("clk_set_pol_seq");
267 |
268 | // set default values for initial and phase delay parameters
269 | if (!_pol.size()) begin
270 | `uvm_warning("CLK_RST_PKG", "\nPolarity not specified. Default value of all zeros used.\n")
271 | _pol = new [_clk_name.size()];
272 | foreach (_pol[i]) begin
273 | _pol[i] = 1'b0;
274 | end
275 | end
276 |
277 | if (!(_seq.randomize() with {
278 | clk_name.size() == _clk_name.size();
279 | foreach(_clk_name[i])
280 | clk_name[i] == _clk_name[i];
281 | init.size() == _pol.size();
282 | foreach(_pol[i])
283 | init[i] == _pol[i];
284 | })) `uvm_error("CLK_RST_PKG", "\nRandomization failed\n")
285 |
286 | if (_print_info) begin
287 | `uvm_info("CLK_RST_PKG", $sformatf({"\nSet Clock Polatiy OP:\n",
288 | "-------------------------------------------------\n",
289 | "OP Type : CLK_SET\n",
290 | "Clock Name(s) : %s\n",
291 | "Clock Num(s) : %s\n",
292 | "Polarity value(s) : %s\n"}
293 | , PrintEnum #(clk_list_t)::printPinEnum(_clk_name, 0)
294 | , PrintEnum #(clk_list_t)::printPinEnum(_clk_name, 1)
295 | , printPinVal(_pol)
296 | ), UVM_LOW)
297 | end
298 |
299 | _seq.start(_sqcr);
300 |
301 | endtask : setClkPol
302 |
303 | //----------------------------------------------------------------------------
304 |
305 | task automatic setRstPol(
306 | input bit _print_info = 1'b1,
307 | input uvm_sequencer_base _sqcr ,
308 | input rst_list_t _rst_name [] ,
309 | input clk_list_t _clk_name [] ,
310 | input logic _pol [] = {} ,
311 | input logic _is_blocking = 1'b1
312 | );
313 |
314 | string _is_blocking_str;
315 | RstSetPolaritySequence _seq;
316 |
317 | if (_sqcr == null) begin
318 | `uvm_error("CLK_RST_PKG", "\nClk agent sequencer handle is NULL\n")
319 | return;
320 | end
321 |
322 | if (_rst_name.size() > R_WIDTH || _rst_name.size() < 1) begin
323 | `uvm_error("CLK_RST_PKG", {"\nOperation ignored.\nNumber of specified resets ",
324 | "is greater than number of actual resets, or is less than one\n"})
325 | return;
326 | end
327 |
328 | if (_clk_name.size() > C_WIDTH || _rst_name.size() < 1 || (_clk_name.size() < C_WIDTH && _clk_name.size() != 1)) begin
329 | `uvm_error("CLK_RST_PKG", {"\nOperation ignored.\nValid number of specified clocks ",
330 | "is either one or an individual clock for all reset signals.\n",
331 | "When one clock is specified it will be used for all specified reset signals.\n"})
332 | return;
333 | end
334 |
335 | _seq = RstSetPolaritySequence::type_id::create("rst_set_pol_seq");
336 |
337 | // regulate clk array
338 | if (_clk_name.size() == 1) begin
339 | clk_list_t tmp;
340 | tmp = _clk_name[0];
341 |
342 | _clk_name = new [_rst_name.size()];
343 | foreach (_clk_name[i]) begin
344 | _clk_name[i] = tmp;
345 | end
346 | end
347 |
348 | // set default values for initial and phase delay parameters
349 | if (!_pol.size()) begin
350 | `uvm_warning("CLK_RST_PKG", "\nPolarity not specified. Default value of all zeros used.\n")
351 | _pol = new [_rst_name.size()];
352 | foreach (_pol[i]) begin
353 | _pol[i] = 1'b0;
354 | end
355 | end
356 |
357 | if (!(_seq.randomize() with {
358 | rst_name.size() == _rst_name.size();
359 | foreach(_rst_name[i])
360 | rst_name[i] == _rst_name[i];
361 | clk_name.size() == _clk_name.size();
362 | foreach(_clk_name[i])
363 | clk_name[i] == _clk_name[i];
364 | init.size() == _pol.size();
365 | foreach(_pol[i])
366 | init[i] == _pol[i];
367 | is_blocking == _is_blocking;
368 | })) `uvm_error("CLK_RST_PKG", "\nRandomization failed\n")
369 |
370 | if (_print_info) begin
371 | _is_blocking_str = (_is_blocking != 1'b0) ? "TRUE" : "FALSE";
372 |
373 | `uvm_info("CLK_RST_PKG", $sformatf({"\nSet Reset Polatiy OP:\n",
374 | "-------------------------------------------------\n",
375 | "OP Type : RST_SET\n",
376 | "Reset Name(s) : %s\n",
377 | "Reset Num(s) : %s\n",
378 | "Polarity value(s) : %s\n",
379 | "Clock Name(s) : %s\n",
380 | "Clock Num(s) : %s\n",
381 | "Blocking : %s\n"}
382 | , PrintEnum #(rst_list_t)::printPinEnum(_rst_name, 0)
383 | , PrintEnum #(rst_list_t)::printPinEnum(_rst_name, 1)
384 | , printPinVal(_pol)
385 | , PrintEnum #(clk_list_t)::printPinEnum(_clk_name, 0)
386 | , PrintEnum #(clk_list_t)::printPinEnum(_clk_name, 1)
387 | , _is_blocking_str
388 | ), UVM_LOW)
389 | end
390 |
391 | _seq.start(_sqcr);
392 |
393 | endtask : setRstPol
394 |
395 | //----------------------------------------------------------------------------
396 |
397 | task automatic waitClkCycles(
398 | input bit _print_info = 1'b1,
399 | input uvm_sequencer_base _sqcr ,
400 | input clk_list_t _clk_name ,
401 | input bit [31:0] _num = 1
402 | );
403 |
404 | ClkWaitCyclesSequence _seq;
405 |
406 | if (_sqcr == null) begin
407 | `uvm_error("CLK_RST_PKG", "\nClk agent sequencer handle is NULL\n")
408 | return;
409 | end
410 |
411 | _seq = ClkWaitCyclesSequence::type_id::create("clk_wait_cycles_seq");
412 |
413 | if (_num < 1) begin
414 | `uvm_warning("CLK_RST_PKG", "\nIncorrect number of cycles value specified. Value of 1 used.\n")
415 | _num = 1;
416 | end
417 |
418 | if (!(_seq.randomize() with {
419 | clk_name.size() == 1;
420 | clk_name[0] == _clk_name;
421 | num == _num;
422 | })) `uvm_error("CLK_RST_PKG", "\nRandomization failed\n")
423 |
424 | if (_print_info) begin
425 | `uvm_info("CLK_RST_PKG", $sformatf({"\nWait Clock Cycles OP:\n",
426 | "-------------------------------------------------\n",
427 | "OP Type : CLK_WAIT\n",
428 | "Clock Name : %s\n",
429 | "Clock Num : %0d\n",
430 | "Num. Cycle(s) : %0d\n"}
431 | , _clk_name.name(), _clk_name, _num
432 | ), UVM_LOW)
433 | end
434 |
435 | _seq.start(_sqcr);
436 |
437 | endtask : waitClkCycles
438 |
439 |
440 | endpackage : ClkAgentPkg
441 |
442 | `endif
443 |
--------------------------------------------------------------------------------
/src/clk_agent_user_pkg.sv:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent user package. This file should be edited by the user
6 | * to specify the user clocks and resets, and set their initial
7 | * values.
8 | */
9 |
10 | `ifndef _AGENT_CLK_RST_USER_PKG_
11 | `define _AGENT_CLK_RST_USER_PKG_
12 |
13 | package ClkAgentUserPkg;
14 |
15 | timeunit 1ns;
16 | timeprecision 100ps;
17 |
18 | //==============================================================================
19 | // User section
20 | //==============================================================================
21 |
22 | // agent output pins list
23 | typedef enum {
24 | SYS_RST,
25 | SYS_RST_N
26 | } rst_list_t;
27 | rst_list_t rst_list;
28 |
29 | typedef enum {
30 | SYS_CLK,
31 | CLK_25_MHz,
32 | CLK_50_MHz
33 | } clk_list_t;
34 | clk_list_t clk_list;
35 |
36 | // if your simulator does not support built-in functions in constant expressions
37 | // please manually count the number of resets and clocks and write it here, and
38 | // delete the *.num() calls,
39 | parameter R_WIDTH = 2; // rst_list.num();
40 | parameter C_WIDTH = 3; // clk_list.num();
41 |
42 | // set the initial values of the Rst output pins
43 | logic [R_WIDTH-1:0] rst_init = {
44 | 1'b1, // SYS_RST
45 | 1'b0 // SYS_RST_N
46 | };
47 |
48 | // set the initial values of the Clk output pins
49 | logic [C_WIDTH-1:0] clk_init = {
50 | 1'b1, // SYS_CLK
51 | 1'b0, // CLK_25_MHz
52 | 1'b0 // CLK_50_MHz
53 | };
54 |
55 | endpackage : ClkAgentUserPkg
56 |
57 | `endif
58 |
--------------------------------------------------------------------------------
/src/clk_if.sv:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Clk agent interface signal definitions. Up to 32 different clock
6 | * sources can be generated.
7 | */
8 |
9 | interface ClkIf();
10 |
11 | timeunit 1ns;
12 | timeprecision 100ps;
13 |
14 | //******************************************************************************
15 | // Ports
16 | //******************************************************************************
17 |
18 | logic [31:0] rst;
19 | logic [31:0] clk;
20 |
21 | endinterface : ClkIf
22 |
--------------------------------------------------------------------------------
/src/sequences/clk_base_sequence.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent base sequence. All other sequences are extended from
6 | * this one.
7 | */
8 |
9 | class ClkBaseSequence extends uvm_sequence #(ClkItem);
10 | `uvm_object_utils(ClkBaseSequence)
11 |
12 | // Variables
13 | ClkItem it;
14 | static int inst_cnt;
15 | rand op_type_t op_type;
16 |
17 | rand rst_list_t rst_name [];
18 | rand clk_list_t clk_name [];
19 | rand logic init [];
20 | rand time period [];
21 | rand time phase_shift [];
22 |
23 | // Constructor
24 | function new(string name = "ClkBaseSequence");
25 | super.new(name);
26 | endfunction: new
27 |
28 | extern virtual task body();
29 |
30 | endclass: ClkBaseSequence
31 |
32 | //******************************************************************************
33 | // Function/Task implementations
34 | //******************************************************************************
35 |
36 | task ClkBaseSequence::body();
37 | inst_cnt++;
38 | it = ClkItem::type_id::create("spi_it");
39 | endtask: body
40 |
--------------------------------------------------------------------------------
/src/sequences/clk_item.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent sequence item.
6 | */
7 |
8 | class ClkItem extends uvm_sequence_item;
9 |
10 | // Variables
11 | rand op_type_t op_type;
12 | rand logic is_blocking; // used only for RST_SET
13 |
14 | rand rst_list_t rst_name [];
15 | rand clk_list_t clk_name [];
16 | rand logic init [];
17 | rand time period [];
18 | rand time phase_shift [];
19 | rand bit [31:0] num;
20 |
21 | // Constructor
22 | function new(string name = "ClkItem");
23 | super.new(name);
24 | endfunction
25 |
26 | `uvm_object_utils_begin(ClkItem)
27 | `uvm_field_enum ( op_type_t, op_type, UVM_DEFAULT | UVM_NOPACK)
28 | `uvm_field_int ( is_blocking, UVM_DEFAULT | UVM_NOPACK)
29 | `uvm_field_array_enum(rst_list_t, rst_name, UVM_DEFAULT | UVM_NOPACK)
30 | `uvm_field_array_enum(clk_list_t, clk_name, UVM_DEFAULT | UVM_NOPACK)
31 | `uvm_field_array_int ( init, UVM_DEFAULT | UVM_NOPACK)
32 | `uvm_field_array_int ( period, UVM_DEFAULT | UVM_NOPACK | UVM_TIME)
33 | `uvm_field_array_int ( phase_shift, UVM_DEFAULT | UVM_NOPACK | UVM_TIME)
34 | `uvm_field_int ( num, UVM_DEFAULT | UVM_NOPACK)
35 | `uvm_object_utils_end
36 |
37 | endclass: ClkItem
38 |
--------------------------------------------------------------------------------
/src/sequences/clk_set_polarity_sequence.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent set polarity sequence. Used to set one or more IDLING
6 | * user defined clocks to a specified value.
7 | */
8 |
9 | class ClkSetPolaritySequence extends ClkStartSequence;
10 | `uvm_object_utils(ClkSetPolaritySequence)
11 |
12 | // Constructor
13 | function new(string name = "ClkSetPolaritySequence");
14 | super.new(name);
15 | endfunction: new
16 |
17 | // Function/Task declarations
18 | extern virtual task body();
19 |
20 | // Constraints
21 | constraint op_type_c {
22 | op_type == CLK_SET;
23 | }
24 |
25 | endclass: ClkSetPolaritySequence
26 |
27 | //******************************************************************************
28 | // Function/Task implementations
29 | //******************************************************************************
30 |
31 | task ClkSetPolaritySequence::body();
32 | super.body(); // call clk start sequence
33 | endtask: body
34 |
--------------------------------------------------------------------------------
/src/sequences/clk_start_sequence.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent start sequence. Used to start generation of one or
6 | * more user defined clocks.
7 | */
8 |
9 | class ClkStartSequence extends ClkBaseSequence;
10 | `uvm_object_utils(ClkStartSequence)
11 |
12 | // Constructor
13 | function new(string name = "ClkStartSequence");
14 | super.new(name);
15 | endfunction: new
16 |
17 | // Function/Task declarations
18 | extern virtual task body();
19 |
20 | // Constraints
21 | constraint op_type_c {
22 | op_type == CLK_START;
23 | }
24 |
25 | endclass: ClkStartSequence
26 |
27 | //******************************************************************************
28 | // Function/Task implementations
29 | //******************************************************************************
30 |
31 | task ClkStartSequence::body();
32 | super.body(); // create the transaction item
33 |
34 | start_item(it);
35 | if (!it.randomize() with {
36 | op_type == local::op_type;
37 | clk_name.size() == local::clk_name.size();
38 | foreach(local::clk_name[i])
39 | clk_name[i] == local::clk_name[i];
40 | init.size() == local::init.size();
41 | foreach(local::init[i])
42 | init[i] == local::init[i];
43 | period.size() == local::period.size();
44 | foreach(local::period[i])
45 | period[i] == local::period[i];
46 | phase_shift.size() == local::phase_shift.size();
47 | foreach(local::phase_shift[i])
48 | phase_shift[i] == local::phase_shift[i];
49 | }) `uvm_error("CLK_START_SQNC", "\nRandomization failed\n")
50 | finish_item(it);
51 | endtask: body
52 |
--------------------------------------------------------------------------------
/src/sequences/clk_stop_sequence.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent stop sequence. Used to stop generation of one or more
6 | * running user defined clocks.
7 | */
8 |
9 | class ClkStopSequence extends ClkBaseSequence;
10 | `uvm_object_utils(ClkStopSequence)
11 |
12 | // Constructor
13 | function new(string name = "ClkStopSequence");
14 | super.new(name);
15 | endfunction: new
16 |
17 | // Function/Task declarations
18 | extern virtual task body();
19 |
20 | // Constraints
21 | constraint op_type_c {
22 | op_type == CLK_STOP;
23 | }
24 |
25 | endclass: ClkStopSequence
26 |
27 | //******************************************************************************
28 | // Function/Task implementations
29 | //******************************************************************************
30 |
31 | task ClkStopSequence::body();
32 | super.body(); // create the transaction item
33 |
34 | start_item(it);
35 | if (!it.randomize() with {
36 | op_type == local::op_type;
37 | clk_name.size() == local::clk_name.size();
38 | foreach(local::clk_name[i])
39 | clk_name[i] == local::clk_name[i];
40 | }) `uvm_error("CLK_STOP_SQNC", "\nRandomization failed\n")
41 | finish_item(it);
42 | endtask: body
43 |
--------------------------------------------------------------------------------
/src/sequences/clk_wait_cycles_sequence.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent wait cycles sequence. Used to wait for one or more clock
6 | * cycles, on a specified user clock.
7 | */
8 |
9 | class ClkWaitCyclesSequence extends ClkBaseSequence;
10 | `uvm_object_utils(ClkWaitCyclesSequence)
11 |
12 | // Variables
13 | rand bit [31:0] num;
14 |
15 | // Constructor
16 | function new(string name = "ClkWaitCyclesSequence");
17 | super.new(name);
18 | endfunction: new
19 |
20 | // Function/Task declarations
21 | extern virtual task body();
22 |
23 | // Constraints
24 | constraint op_type_c {
25 | op_type == CLK_WAIT;
26 | }
27 |
28 | endclass: ClkWaitCyclesSequence
29 |
30 | //******************************************************************************
31 | // Function/Task implementations
32 | //******************************************************************************
33 |
34 | task ClkWaitCyclesSequence::body();
35 | super.body(); // create the transaction item
36 |
37 | start_item(it);
38 | if (!it.randomize() with {
39 | op_type == local::op_type;
40 | clk_name.size() == local::clk_name.size();
41 | foreach(local::clk_name[i])
42 | clk_name[i] == local::clk_name[i];
43 | num == local::num;
44 | }) `uvm_error("CLK_WAIT_SQNC", "\nRandomization failed\n")
45 | finish_item(it);
46 | endtask: body
47 |
--------------------------------------------------------------------------------
/src/sequences/rst_set_polarity_sequence.svh:
--------------------------------------------------------------------------------
1 | /* AUTHOR : Ivan Mokanj
2 | * START DATE : 2017
3 | * LICENSE : LGPLv3
4 | *
5 | * DESCRIPTION : Agent set reset polarity sequence. Used to set one or more
6 | * user defined resets to a specified value.
7 | */
8 |
9 | class RstSetPolaritySequence extends ClkBaseSequence;
10 | `uvm_object_utils(RstSetPolaritySequence)
11 |
12 | // Variables
13 | rand logic is_blocking;
14 |
15 | // Constructor
16 | function new(string name = "RstSetPolaritySequence");
17 | super.new(name);
18 | endfunction: new
19 |
20 | // Function/Task declarations
21 | extern virtual task body();
22 |
23 | // Constraints
24 | constraint op_type_c {
25 | op_type == RST_SET;
26 | }
27 |
28 | endclass: RstSetPolaritySequence
29 |
30 | //******************************************************************************
31 | // Function/Task implementations
32 | //******************************************************************************
33 |
34 | task RstSetPolaritySequence::body();
35 | super.body(); // create the transaction item
36 |
37 | start_item(it);
38 | if (!it.randomize() with {
39 | op_type == local::op_type;
40 | rst_name.size() == local::rst_name.size();
41 | foreach(local::rst_name[i])
42 | rst_name[i] == local::rst_name[i];
43 | clk_name.size() == local::clk_name.size();
44 | foreach(local::clk_name[i])
45 | clk_name[i] == local::clk_name[i];
46 | init.size() == local::init.size();
47 | foreach(local::init[i])
48 | init[i] == local::init[i];
49 | is_blocking == local::is_blocking;
50 | }) `uvm_error("RST_SET_SQNC", "\nRandomization failed\n")
51 | finish_item(it);
52 | endtask: body
53 |
--------------------------------------------------------------------------------