├── README.md ├── sim ├── Makefile └── top.sv ├── include ├── yuu_clock_defines.svh ├── yuu_clock_interface.svi └── yuu_clock_pkg.sv ├── src └── sv │ └── yuu_clock_agent │ ├── yuu_clock_item.sv │ ├── yuu_clock_agent.sv │ ├── yuu_clock_driver.sv │ ├── yuu_clock_config.sv │ └── yuu_clock_monitor.sv └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # yuu_clock 2 | UVM clock agent 3 | 4 | ## Features 5 | 1. Duty cycle can be configured. 6 | 2. Slow clock enable for IDLE clock etc. 7 | 3. Clock gating 8 | 4. Clock divider mode 9 | 5. Clock multiplier mode 10 | 11 | ## Note 12 | [yuu_common](https://github.com/seabeam/yuu_common "YUU UVM utilities package") package is needed -------------------------------------------------------------------------------- /sim/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | @rm .[a-zA-Z]* -rf 3 | @ls | grep -v Makefile | grep -v top.sv | xargs rm -rf 4 | @echo clean done 5 | 6 | comp: 7 | vcs -sverilog -full64 -lca -kdb -q -ntb_opts uvm -debug_access+all ../../yuu_common/include/yuu_common_pkg.sv ../include/yuu_clock_pkg.sv +incdir+../../yuu_common/include +incdir+../../yuu_common/src/sv +incdir+../src/sv/yuu_clock_agent +incdir+../include top.sv -timescale=1ps/1ps -l comp.log 8 | 9 | run: 10 | simv -l run.log ${ADD} -------------------------------------------------------------------------------- /include/yuu_clock_defines.svh: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_CLOCK_DEFINES_SVH 6 | `define YUU_CLOCK_DEFINES_SVH 7 | 8 | `ifndef YUU_CLOCK_MAX_DIVIDE 9 | `define YUU_CLOCK_MAX_DIVIDE 16 10 | `endif 11 | 12 | `ifndef YUU_CLOCK_MAX_MULTI 13 | `define YUU_CLOCK_MAX_MULTI 16 14 | `endif 15 | 16 | `endif -------------------------------------------------------------------------------- /include/yuu_clock_interface.svi: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_CLOCK_INTERFACE_SVI 6 | `define YUU_CLOCK_INTERFACE_SVI 7 | 8 | interface yuu_clock_interface(); 9 | logic clk_i; 10 | logic clk_o; 11 | logic enable; 12 | logic slow; 13 | logic ready; 14 | logic [7:0] divide_num; 15 | logic [7:0] multi_factor; 16 | logic measure_enable; 17 | endinterface 18 | 19 | `endif -------------------------------------------------------------------------------- /include/yuu_clock_pkg.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_CLOCK_PKG_SV 6 | `define YUU_CLOCK_PKG_SV 7 | 8 | `include "yuu_clock_defines.svh" 9 | `include "yuu_clock_interface.svi" 10 | 11 | package yuu_clock_pkg; 12 | import uvm_pkg::*; 13 | `include "uvm_macros.svh" 14 | 15 | import yuu_common_pkg::*; 16 | 17 | `include "yuu_clock_config.sv" 18 | `include "yuu_clock_item.sv" 19 | `include "yuu_clock_driver.sv" 20 | `include "yuu_clock_monitor.sv" 21 | `include "yuu_clock_agent.sv" 22 | endpackage 23 | 24 | `endif -------------------------------------------------------------------------------- /src/sv/yuu_clock_agent/yuu_clock_item.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2020 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_CLOCK_ITEM_SV 6 | `define YUU_CLOCK_ITEM_SV 7 | 8 | class yuu_clock_item extends uvm_sequence_item; 9 | yuu_clock_config cfg; 10 | 11 | real freq; 12 | real duty; 13 | string unit; 14 | 15 | `uvm_object_utils_begin(yuu_clock_item) 16 | `uvm_field_real (freq, UVM_ALL_ON) 17 | `uvm_field_real (duty, UVM_ALL_ON) 18 | `uvm_field_string (unit, UVM_ALL_ON) 19 | `uvm_object_utils_end 20 | 21 | function new(string name="yuu_clock_item"); 22 | super.new(name); 23 | endfunction 24 | 25 | endclass 26 | 27 | `endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 seabeam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/sv/yuu_clock_agent/yuu_clock_agent.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_CLOCK_AGENT_SV 6 | `define YUU_CLOCK_AGENT_SV 7 | 8 | class yuu_clock_agent extends uvm_agent; 9 | yuu_clock_config cfg; 10 | 11 | yuu_clock_driver driver; 12 | yuu_clock_monitor monitor; 13 | 14 | uvm_analysis_port #(yuu_clock_item) out_monitor_ap; 15 | 16 | `uvm_component_utils(yuu_clock_agent) 17 | 18 | extern function new(string name, uvm_component parent); 19 | extern virtual function void build_phase(uvm_phase phase); 20 | extern virtual function void connect_phase(uvm_phase phase); 21 | endclass 22 | 23 | function yuu_clock_agent::new(string name, uvm_component parent); 24 | super.new(name, parent); 25 | endfunction 26 | 27 | function void yuu_clock_agent::build_phase(uvm_phase phase); 28 | if (!uvm_config_db #(yuu_clock_config)::get(null, get_full_name(), "cfg", cfg)) 29 | `uvm_fatal("build_phase", "Cannot get clock configuration") 30 | if (cfg == null) 31 | `uvm_fatal("build_phase", "Get a null clock configuration") 32 | 33 | if (cfg.is_active == UVM_ACTIVE) begin 34 | driver = yuu_clock_driver::type_id::create("driver", this); 35 | driver.cfg = cfg; 36 | end 37 | monitor = yuu_clock_monitor::type_id::create("monitor", this); 38 | monitor.cfg = cfg; 39 | endfunction 40 | 41 | function void yuu_clock_agent::connect_phase(uvm_phase phase); 42 | out_monitor_ap = monitor.out_monitor_ap; 43 | endfunction 44 | 45 | `endif -------------------------------------------------------------------------------- /src/sv/yuu_clock_agent/yuu_clock_driver.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_CLOCK_DRIVER_SV 6 | `define YUU_CLOCK_DRIVER_SV 7 | 8 | class yuu_clock_driver extends uvm_driver#(uvm_sequence_item); 9 | virtual yuu_clock_interface vif; 10 | 11 | yuu_clock_config cfg; 12 | uvm_event_pool events; 13 | 14 | protected real m_slow_freq; 15 | protected real m_fast_freq; 16 | protected real m_duty; 17 | protected string m_clock_unit; 18 | protected bit m_clk_now; 19 | 20 | `uvm_component_utils(yuu_clock_driver) 21 | 22 | extern function new(string name, uvm_component parent); 23 | extern virtual function void build_phase(uvm_phase phase); 24 | extern virtual function void connect_phase(uvm_phase phase); 25 | extern virtual task run_phase(uvm_phase phase); 26 | extern virtual task init_component(); 27 | extern virtual task count_time(); 28 | extern virtual task delay_unit(real delay); 29 | endclass 30 | 31 | function yuu_clock_driver::new(string name, uvm_component parent); 32 | super.new(name, parent); 33 | endfunction 34 | 35 | function void yuu_clock_driver::build_phase(uvm_phase phase); 36 | if (cfg == null) 37 | `uvm_fatal("build_phase", "Check the yuu_clock agent configure setting") 38 | endfunction 39 | 40 | function void yuu_clock_driver::connect_phase(uvm_phase phase); 41 | vif = cfg.vif; 42 | events = cfg.events; 43 | endfunction 44 | 45 | task yuu_clock_driver::run_phase(uvm_phase phase); 46 | init_component(); 47 | 48 | m_clk_now = cfg.init_val; 49 | #(cfg.get_phase()); 50 | m_slow_freq = cfg.get_slow_freq(); 51 | m_fast_freq = cfg.get_fast_freq(); 52 | m_duty = cfg.get_duty(); 53 | m_clock_unit= cfg.get_unit(); 54 | vif.divide_num <= cfg.divide_num; 55 | vif.multi_factor<= cfg.multi_factor; 56 | vif.ready <= 1'b1; 57 | 58 | forever begin 59 | if (vif.enable === 1'b0 && cfg.gating_enable) begin 60 | vif.clk_o <= 1'b0; 61 | wait(vif.enable === 1'b1); 62 | end 63 | else 64 | count_time(); 65 | end 66 | endtask 67 | 68 | 69 | task yuu_clock_driver::init_component(); 70 | uvm_event init_done = events.get($sformatf("%s_init_done", cfg.get_name())); 71 | 72 | init_done.wait_on(); 73 | cfg.check_valid(); 74 | if (cfg.divider_mode || cfg.multiplier_mode) begin 75 | cfg.init_val = 1'b1; 76 | end 77 | vif.clk_o <= cfg.init_val; 78 | vif.divide_num <= 'h0; 79 | vif.multi_factor<= 'h0; 80 | vif.ready <= 1'b0; 81 | endtask 82 | 83 | task yuu_clock_driver::count_time(); 84 | if (m_clk_now == 1'b1) begin 85 | if (vif.slow === 1'b1 && cfg.slow_enable) 86 | delay_unit(real'(1000)/m_slow_freq * m_duty); 87 | else 88 | delay_unit(real'(1000)/m_fast_freq * m_duty); 89 | vif.clk_o <= 1'b0; 90 | m_clk_now = 1'b0; 91 | end 92 | else if (m_clk_now == 1'b0) begin 93 | if (vif.slow === 1'b1 && cfg.slow_enable) 94 | delay_unit(real'(1000)/m_slow_freq * (real'(1)-m_duty)); 95 | else 96 | delay_unit(real'(1000)/m_fast_freq * (real'(1)-m_duty)); 97 | vif.clk_o <= 1'b1; 98 | m_clk_now = 1'b1; 99 | end 100 | endtask 101 | 102 | task yuu_clock_driver::delay_unit(real delay); 103 | real unit; 104 | 105 | case(m_clock_unit) 106 | "G": unit = 1ps; 107 | "M": unit = 1ns; 108 | "K": unit = 1us; 109 | default: unit = 1ms; 110 | endcase 111 | 112 | #(delay*unit); 113 | endtask 114 | 115 | `endif -------------------------------------------------------------------------------- /sim/top.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | import uvm_pkg::*; 6 | `include "uvm_macros.svh" 7 | 8 | import yuu_common_pkg::*; 9 | import yuu_clock_pkg::*; 10 | 11 | class uvc_test extends uvm_test; 12 | virtual yuu_clock_interface clk_vif0; 13 | virtual yuu_clock_interface clk_vif1; 14 | virtual yuu_clock_interface clk_vif2; 15 | virtual yuu_clock_interface clk_vif3; 16 | uvm_event_pool events; 17 | 18 | yuu_clock_agent agent0; 19 | yuu_clock_agent agent1; 20 | yuu_clock_agent agent2; 21 | yuu_clock_agent agent3; 22 | 23 | `uvm_component_utils(uvc_test) 24 | 25 | function new(string name, uvm_component parent); 26 | super.new(name, parent); 27 | endfunction 28 | 29 | function void build_phase(uvm_phase phase); 30 | yuu_clock_config cfg0 = new("cfg0"); 31 | yuu_clock_config cfg1 = new("cfg1"); 32 | yuu_clock_config cfg2 = new("cfg2"); 33 | yuu_clock_config cfg3 = new("cfg3"); 34 | 35 | events = new("events"); 36 | uvm_config_db#(virtual yuu_clock_interface)::get(null, get_full_name(), "vif0", cfg0.vif); 37 | clk_vif0 = cfg0.vif; 38 | cfg0.set_freq(2, 1); 39 | cfg0.set_duty(0.3); 40 | cfg0.set_unit("M"); 41 | cfg0.init_val = 1'b0; 42 | cfg0.enable_clock_slow(True); 43 | cfg0.enable_clock_gating(True); 44 | cfg0.events = events; 45 | uvm_config_db#(yuu_clock_config)::set(this, "agent0", "cfg", cfg0); 46 | agent0 = new("agent0", this); 47 | 48 | uvm_config_db#(virtual yuu_clock_interface)::get(null, get_full_name(), "vif1", cfg1.vif); 49 | clk_vif1 = cfg1.vif; 50 | cfg1.set_freq(800); 51 | cfg1.set_duty(0.5); 52 | cfg1.set_phase(4000); 53 | cfg1.set_unit("K"); 54 | cfg1.init_val = 1'b1; 55 | cfg1.enable_clock_slow(False); 56 | cfg1.enable_clock_gating(False); 57 | cfg1.events = events; 58 | uvm_config_db#(yuu_clock_config)::set(this, "agent1", "cfg", cfg1); 59 | agent1 = new("agent1", this); 60 | 61 | uvm_config_db#(virtual yuu_clock_interface)::get(null, get_full_name(), "vif2", cfg2.vif); 62 | clk_vif2 = cfg2.vif; 63 | cfg2.multiplier_mode = True; 64 | cfg2.enable_clock_slow(False); 65 | cfg2.enable_clock_gating(False); 66 | cfg2.events = events; 67 | cfg2.multi_factor = 3; 68 | uvm_config_db#(yuu_clock_config)::set(this, "agent2", "cfg", cfg2); 69 | agent2 = new("agent2", this); 70 | 71 | uvm_config_db#(virtual yuu_clock_interface)::get(null, get_full_name(), "vif3", cfg3.vif); 72 | clk_vif3 = cfg3.vif; 73 | cfg3.divider_mode = True; 74 | cfg3.enable_clock_slow(False); 75 | cfg3.enable_clock_gating(False); 76 | cfg3.events = events; 77 | cfg3.divide_num = 2; 78 | uvm_config_db#(yuu_clock_config)::set(this, "agent3", "cfg", cfg3); 79 | agent3 = new("agent3", this); 80 | endfunction 81 | 82 | task run_phase(uvm_phase phase); 83 | fork 84 | begin 85 | phase.raise_objection(this); 86 | repeat(100) @(posedge clk_vif3.clk_o); 87 | phase.drop_objection(this); 88 | end 89 | event_process(); 90 | join 91 | endtask 92 | 93 | task event_process(); 94 | uvm_event e0 = events.get("cfg_clock_slow"); 95 | uvm_event e1 = events.get("cfg_clock_fast"); 96 | 97 | fork 98 | while(1) begin 99 | e0.wait_trigger(); 100 | $display("Clock slow @ %0t", $realtime()); 101 | end 102 | while(1) begin 103 | e1.wait_trigger(); 104 | $display("Clock fast @ %0t", $realtime()); 105 | end 106 | join 107 | endtask 108 | endclass 109 | 110 | module top; 111 | yuu_clock_interface cif0(); 112 | yuu_clock_interface cif1(); 113 | yuu_clock_interface cif2(); 114 | yuu_clock_interface cif3(); 115 | 116 | initial begin 117 | uvm_config_db#(virtual yuu_clock_interface)::set(null, "", "vif0", cif0); 118 | uvm_config_db#(virtual yuu_clock_interface)::set(null, "", "vif1", cif1); 119 | uvm_config_db#(virtual yuu_clock_interface)::set(null, "", "vif2", cif2); 120 | uvm_config_db#(virtual yuu_clock_interface)::set(null, "", "vif3", cif3); 121 | run_test("uvc_test"); 122 | end 123 | 124 | logic clk_ext; 125 | always begin 126 | if (clk_ext == 1) 127 | #200ns clk_ext = ~clk_ext; 128 | else 129 | #800ns clk_ext = ~clk_ext; 130 | end 131 | 132 | assign cif2.clk_i = clk_ext; 133 | assign cif3.clk_i = clk_ext; 134 | 135 | initial begin 136 | clk_ext = 0; 137 | 138 | cif0.measure_enable = 1; 139 | cif1.measure_enable = 1; 140 | cif2.measure_enable = 1; 141 | cif3.measure_enable = 1; 142 | cif0.enable = 1'b0; 143 | cif0.slow = 1'b1; 144 | #5ns; 145 | cif0.enable = 1'b1; 146 | while(1) begin 147 | #600ns; 148 | cif0.slow = $urandom(); 149 | #500ns; 150 | cif0.enable = $urandom(); 151 | end 152 | end 153 | endmodule 154 | -------------------------------------------------------------------------------- /src/sv/yuu_clock_agent/yuu_clock_config.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_CLOCK_CONFIG_SV 6 | `define YUU_CLOCK_CONFIG_SV 7 | 8 | class yuu_clock_config extends uvm_object; 9 | virtual yuu_clock_interface vif; 10 | uvm_event_pool events; 11 | 12 | logic init_val = 1'b0; 13 | protected real m_slow_freq; 14 | protected real m_fast_freq; 15 | protected real m_duty = 0.5; 16 | protected real m_phase; 17 | bit [7:0] divide_num = 1; 18 | bit [7:0] multi_factor = 1; 19 | protected string m_unit = "M"; 20 | 21 | boolean slow_enable = False; 22 | boolean gating_enable= False; 23 | boolean divider_mode = False; 24 | boolean multiplier_mode = False; 25 | 26 | uvm_active_passive_enum is_active = UVM_ACTIVE; 27 | 28 | `uvm_object_utils_begin(yuu_clock_config) 29 | `uvm_field_int ( init_val, UVM_ALL_ON) 30 | `uvm_field_real ( m_slow_freq, UVM_ALL_ON) 31 | `uvm_field_real ( m_fast_freq, UVM_ALL_ON) 32 | `uvm_field_real ( m_duty, UVM_ALL_ON) 33 | `uvm_field_real ( m_phase, UVM_ALL_ON) 34 | `uvm_field_string ( m_unit, UVM_ALL_ON) 35 | `uvm_field_int ( divide_num, UVM_ALL_ON) 36 | `uvm_field_int ( multi_factor, UVM_ALL_ON) 37 | `uvm_field_enum (boolean, slow_enable, UVM_ALL_ON) 38 | `uvm_field_enum (boolean, gating_enable, UVM_ALL_ON) 39 | `uvm_field_enum (boolean, divider_mode, UVM_ALL_ON) 40 | `uvm_field_enum (boolean, multiplier_mode,UVM_ALL_ON) 41 | `uvm_field_enum (uvm_active_passive_enum, is_active, UVM_ALL_ON) 42 | `uvm_object_utils_end 43 | 44 | extern function new(string name="yuu_clock_config"); 45 | extern virtual function void set_duty(real duty); 46 | extern virtual function real get_duty(); 47 | extern virtual function void set_freq(real fast, real slow=0); 48 | extern virtual function real get_freq(); 49 | extern virtual function real get_fast_freq(); 50 | extern virtual function real get_slow_freq(); 51 | extern virtual function void set_phase(real phase); 52 | extern virtual function real get_phase(); 53 | extern virtual function void enable_clock_slow(boolean on_off); 54 | extern virtual function void enable_clock_gating(boolean on_off); 55 | extern virtual function void set_unit(string unit); 56 | extern virtual function string get_unit(); 57 | extern virtual function boolean check_valid(); 58 | endclass 59 | 60 | function yuu_clock_config::new(string name="yuu_clock_config"); 61 | super.new(name); 62 | endfunction 63 | 64 | function void yuu_clock_config::set_duty(real duty); 65 | if (duty >= 1 || duty <= 0) 66 | `uvm_warning("set_duty", "The clock duty cycle only can be set in range (0, 1), setting ignored") 67 | else begin 68 | this.m_duty = duty; 69 | `uvm_info("set_duty", $sformatf("The clock duty cycle set to %f", duty), UVM_MEDIUM) 70 | end 71 | endfunction 72 | 73 | function real yuu_clock_config::get_duty(); 74 | return this.m_duty; 75 | endfunction 76 | 77 | function void yuu_clock_config::set_freq(real fast, real slow=0); 78 | this.m_fast_freq = fast; 79 | this.m_slow_freq = slow; 80 | `uvm_info("set_freq", $sformatf("The clock frequency set to [fast:%0f low:%0f])", fast, slow), UVM_MEDIUM) 81 | endfunction 82 | 83 | function real yuu_clock_config::get_freq(); 84 | return get_fast_freq(); 85 | endfunction 86 | 87 | function real yuu_clock_config::get_fast_freq(); 88 | return this.m_fast_freq; 89 | endfunction 90 | 91 | function real yuu_clock_config::get_slow_freq(); 92 | return this.m_slow_freq; 93 | endfunction 94 | 95 | function void yuu_clock_config::set_phase(real phase); 96 | this.m_phase = phase; 97 | endfunction 98 | 99 | function real yuu_clock_config::get_phase(); 100 | return m_phase; 101 | endfunction 102 | 103 | function void yuu_clock_config::enable_clock_slow(boolean on_off); 104 | string state = on_off ? "ON" : "OFF"; 105 | 106 | this.slow_enable = on_off; 107 | `uvm_info("enable_clock_slow", $sformatf("The clock slow down function is %s", state), UVM_MEDIUM) 108 | endfunction 109 | 110 | function void yuu_clock_config::enable_clock_gating(boolean on_off); 111 | string state = on_off ? "ON" : "OFF"; 112 | 113 | this.gating_enable = on_off; 114 | `uvm_info("enable_clock_gating", $sformatf("The clock gating function is %s", state), UVM_MEDIUM) 115 | endfunction 116 | 117 | function void yuu_clock_config::set_unit(string unit); 118 | m_unit = unit.toupper(); 119 | endfunction 120 | 121 | function string yuu_clock_config::get_unit(); 122 | return m_unit; 123 | endfunction 124 | 125 | function boolean yuu_clock_config::check_valid(); 126 | if (m_slow_freq <= 0 && slow_enable) begin 127 | `uvm_fatal("check_valid", "The slow frequency should be set up 0 when clock slow down enable") 128 | return False; 129 | end 130 | if (m_slow_freq > m_fast_freq) begin 131 | `uvm_fatal("check_valid", "The slow frequency should be lower than fast frequency") 132 | return False; 133 | end 134 | if (m_fast_freq <= 0) begin 135 | `uvm_fatal("check_valid", "The fast frequency should be higher then 0") 136 | return False; 137 | end 138 | if (divider_mode & multiplier_mode) begin 139 | `uvm_fatal("check_valid", "It cannot enable divider mode and multiplier mode at the same time") 140 | return False; 141 | end 142 | if (divide_num == 0 && divider_mode) begin 143 | `uvm_fatal("check_valid", "The divide number should be a positive data when divider mode is enable") 144 | return False; 145 | end 146 | if (multi_factor == 0 && multiplier_mode) begin 147 | `uvm_fatal("check_valid", "The multiply factor should be a positive data when multiplier mode is enable") 148 | return False; 149 | end 150 | if (!(m_unit inside {"", "K", "M", "G"})) begin 151 | `uvm_fatal("check_valid", "The acceptable clock time unit is empty string, K, M or G") 152 | return False; 153 | end 154 | 155 | return True; 156 | endfunction 157 | 158 | `endif 159 | -------------------------------------------------------------------------------- /src/sv/yuu_clock_agent/yuu_clock_monitor.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_CLOCK_MONITOR_SV 6 | `define YUU_CLOCK_MONITOR_SV 7 | 8 | class yuu_clock_monitor extends uvm_monitor; 9 | virtual yuu_clock_interface vif; 10 | 11 | yuu_clock_config cfg; 12 | uvm_event_pool events; 13 | 14 | uvm_analysis_port #(yuu_clock_item) out_monitor_ap; 15 | 16 | `uvm_component_utils(yuu_clock_monitor) 17 | 18 | extern function new(string name, uvm_component parent); 19 | extern virtual function void build_phase(uvm_phase phase); 20 | extern virtual function void connect_phase(uvm_phase phase); 21 | extern virtual task run_phase(uvm_phase phase); 22 | extern virtual task init_component(); 23 | extern virtual task monitor_gating(); 24 | extern virtual task monitor_slow(); 25 | extern virtual task measure_input(output real duty, output real freq, output string unit); 26 | extern virtual function void reconfig_mult(input real t0, input real t1, input real t2, output real duty, output real freq, output string unit); 27 | extern virtual function void reconfig_div(input real t0, input real t1, input real t2, output real duty, output real freq, output string unit); 28 | extern virtual function string get_sim_time_unit(); 29 | endclass 30 | 31 | function yuu_clock_monitor::new(string name, uvm_component parent); 32 | super.new(name, parent); 33 | endfunction 34 | 35 | function void yuu_clock_monitor::build_phase(uvm_phase phase); 36 | out_monitor_ap = new("out_monitor_ap", this); 37 | endfunction 38 | 39 | function void yuu_clock_monitor::connect_phase(uvm_phase phase); 40 | vif = cfg.vif; 41 | events = cfg.events; 42 | endfunction 43 | 44 | task yuu_clock_monitor::run_phase(uvm_phase phase); 45 | init_component(); 46 | 47 | fork 48 | monitor_gating(); 49 | monitor_slow(); 50 | forever begin 51 | fork 52 | wait(vif.measure_enable === 1'b0); 53 | begin 54 | real duty; 55 | real freq; 56 | string unit; 57 | yuu_clock_item monitor_item = yuu_clock_item::type_id::create("monitor_item"); 58 | 59 | measure_input(duty, freq, unit); 60 | monitor_item.duty = duty; 61 | monitor_item.freq = freq; 62 | monitor_item.unit = unit; 63 | out_monitor_ap.write(monitor_item); 64 | end 65 | join_any 66 | disable fork; 67 | end 68 | join 69 | endtask 70 | 71 | 72 | task yuu_clock_monitor::init_component(); 73 | real duty; 74 | real freq; 75 | string unit; 76 | uvm_event init_done = events.get($sformatf("%s_init_done", cfg.get_name())); 77 | 78 | if (cfg.divider_mode || cfg.multiplier_mode) begin 79 | measure_input(duty, freq, unit); 80 | cfg.set_freq(freq); 81 | cfg.set_unit(unit); 82 | cfg.set_duty(duty); 83 | end 84 | init_done.trigger(); 85 | endtask 86 | 87 | task yuu_clock_monitor::monitor_gating(); 88 | uvm_event e0 = events.get($sformatf("%s_yuu_clock_enable", cfg.get_name())); 89 | uvm_event e1 = events.get($sformatf("%s_yuu_clock_gating", cfg.get_name())); 90 | 91 | forever begin 92 | @(vif.enable); 93 | if (vif.enable === 1'b1) begin 94 | e0.trigger(); 95 | `uvm_info("monitor_gating", $sformatf("%s clock turn on", cfg.get_name()), UVM_MEDIUM) 96 | end 97 | else if (vif.enable === 1'b0) begin 98 | e1.trigger(); 99 | `uvm_info("monitor_gating", $sformatf("%s clock turn off", cfg.get_name()), UVM_MEDIUM) 100 | end 101 | end 102 | endtask 103 | 104 | task yuu_clock_monitor::monitor_slow(); 105 | uvm_event e0 = events.get($sformatf("%s_yuu_clock_slow", cfg.get_name())); 106 | uvm_event e1 = events.get($sformatf("%s_yuu_clock_fast", cfg.get_name())); 107 | 108 | forever begin 109 | @(vif.slow); 110 | if (vif.slow === 1'b1) begin 111 | e0.trigger(); 112 | `uvm_info("monitor_slow", $sformatf("%s clock turn down", cfg.get_name()), UVM_MEDIUM) 113 | end 114 | else if (vif.slow === 1'b0) begin 115 | e1.trigger(); 116 | `uvm_info("monitor_slow", $sformatf("%s clock turn up", cfg.get_name()), UVM_MEDIUM) 117 | end 118 | end 119 | endtask 120 | 121 | // --------- ---- 122 | // | | | 123 | //----- ------------ 124 | // t0 t1 t2 125 | task yuu_clock_monitor::measure_input(output real duty, 126 | output real freq, 127 | output string unit); 128 | real t0, t1, t2; 129 | 130 | wait(vif.clk_i === 1'b1); 131 | t0 = $realtime(); 132 | //$display(t0); 133 | wait(vif.clk_i === 1'b0); 134 | t1 = $realtime(); 135 | //$display(t1); 136 | wait(vif.clk_i === 1'b1); 137 | t2 = $realtime(); 138 | //$display(t2); 139 | 140 | if (cfg.multiplier_mode) begin 141 | reconfig_mult(t0, t1, t2, duty, freq, unit); 142 | end 143 | else begin 144 | reconfig_div(t0, t1, t2, duty, freq, unit); 145 | end 146 | endtask 147 | 148 | function void yuu_clock_monitor::reconfig_mult( input real t0, 149 | input real t1, 150 | input real t2, 151 | output real duty, 152 | output real freq, 153 | output string unit); 154 | real T; 155 | real ofm; 156 | string time_unit = get_sim_time_unit(); 157 | 158 | T = t2-t0; 159 | duty = (t1-t0)/T; 160 | ofm = $log10(T); 161 | if (ofm < 3) begin 162 | freq = real'(1000)/T*real'(cfg.multi_factor); 163 | case(time_unit) 164 | "s": unit = ""; 165 | "ms": unit = ""; 166 | "us": unit = "K"; 167 | "ns": unit = "M"; 168 | "ps": unit = "G"; 169 | "fs": unit = "G"; 170 | endcase 171 | end 172 | else if (ofm >= 3 && ofm < 6) begin 173 | freq = real'(1000)/(T/real'(1000))*real'(cfg.multi_factor); 174 | case(time_unit) 175 | "s": unit = ""; 176 | "ms": unit = ""; 177 | "us": unit = ""; 178 | "ns": unit = "K"; 179 | "ps": unit = "M"; 180 | "fs": unit = "G"; 181 | endcase 182 | end 183 | else if (ofm >= 6 && ofm < 9) begin 184 | freq = real'(1000)/(T/real'(1000000))*real'(cfg.multi_factor); 185 | case(time_unit) 186 | "s": unit = ""; 187 | "ms": unit = ""; 188 | "us": unit = ""; 189 | "ns": unit = ""; 190 | "ps": unit = "K"; 191 | "fs": unit = "M"; 192 | endcase 193 | end 194 | else begin 195 | freq = real'(1000)/(T/real'(1000000000))*real'(cfg.multi_factor); 196 | case(time_unit) 197 | "s": unit = ""; 198 | "ms": unit = ""; 199 | "us": unit = ""; 200 | "ns": unit = ""; 201 | "ps": unit = ""; 202 | "fs": unit = "K"; 203 | endcase 204 | end 205 | endfunction 206 | 207 | function void yuu_clock_monitor::reconfig_div(input real t0, 208 | input real t1, 209 | input real t2, 210 | output real duty, 211 | output real freq, 212 | output string unit); 213 | real T; 214 | real ofm; 215 | string time_unit = get_sim_time_unit(); 216 | 217 | T = t2-t0; 218 | duty = (t1-t0)/T; 219 | ofm = $log10(T); 220 | if (ofm < 3) begin 221 | freq = real'(1000)/T/real'(cfg.divide_num); 222 | case(time_unit) 223 | "s": unit = ""; 224 | "ms": unit = ""; 225 | "us": unit = "K"; 226 | "ns": unit = "M"; 227 | "ps": unit = "G"; 228 | "fs": unit = "G"; 229 | endcase 230 | end 231 | else if (ofm >= 3 && ofm < 6) begin 232 | freq = real'(1000)/(T/real'(1000))/real'(cfg.divide_num); 233 | case(time_unit) 234 | "s": unit = ""; 235 | "ms": unit = ""; 236 | "us": unit = ""; 237 | "ns": unit = "K"; 238 | "ps": unit = "M"; 239 | "fs": unit = "G"; 240 | endcase 241 | end 242 | else if (ofm >= 6 && ofm < 9) begin 243 | freq = real'(1000)/(T/real'(1000000))/real'(cfg.divide_num); 244 | case(time_unit) 245 | "s": unit = ""; 246 | "ms": unit = ""; 247 | "us": unit = ""; 248 | "ns": unit = ""; 249 | "ps": unit = "K"; 250 | "fs": unit = "M"; 251 | endcase 252 | end 253 | else begin 254 | freq = real'(1000)/(T/real'(1000000000))/real'(cfg.divide_num); 255 | case(time_unit) 256 | "s": unit = ""; 257 | "ms": unit = ""; 258 | "us": unit = ""; 259 | "ns": unit = ""; 260 | "ps": unit = ""; 261 | "fs": unit = "K"; 262 | endcase 263 | end 264 | endfunction 265 | 266 | function string yuu_clock_monitor::get_sim_time_unit(); 267 | int test_time; 268 | 269 | test_time = 100ms; 270 | if (test_time == 0) 271 | return "s"; 272 | test_time = 100us; 273 | if (test_time == 0) 274 | return "ms"; 275 | test_time = 100ns; 276 | if (test_time == 0) 277 | return "us"; 278 | test_time = 100ps; 279 | if (test_time == 0) 280 | return "ns"; 281 | test_time = 100fs; 282 | if (test_time == 0) 283 | return "ps"; 284 | 285 | return "fs"; 286 | endfunction 287 | 288 | `endif --------------------------------------------------------------------------------