[CU]uvm lab5-router
注1:uvm lab1 - __见贤思齐 - 博客园 (cnblogs.com)
注2:uvm lab2 - __见贤思齐 - 博客园 (cnblogs.com)
注3:uvm lab3 - __见贤思齐 - 博客园 (cnblogs.com)
注4:uvm lab4 - __见贤思齐 - 博客园 (cnblogs.com)
注5:uvm1.1 lab链接第三方资源 – 路科验证 (rockeric.com).
注6:synopsys uvm1.2 lab guide - IC验证资料 - EETOP 创芯网论坛 (原名:电子顶级开发网) -
注7:uvm1.2 lab链接UVM1.2 Lab验证资料(入门必备) - IC验证资料 - EETOP 创芯网论坛 (原名:电子顶级开发网) -
学习目标
(1) 在monitor中实现TLM analysis port;
(2) 采用uvm_in_order_class_comparator实现uvm_scoreboard;
(3) virtual sequence和virtual sequencer的使用;
1.test.sv
1 program automatic test; 2 import uvm_pkg::*; 3 4 `include "test_collection.sv" 5 6 initial begin 7 $timeformat(-9, 1, "ns", 10); 8 run_test(); 9 end 10 11 endprogram
2.test_collection.sv(派生于uvm_test)
注1:注意main_phase中set_drain_time的使用;
1 `ifndef TEST_COLLECTION__SV 2 `define TEST_COLLECTION__SV 3 4 `include "router_env.sv" 5 6 class test_base extends uvm_test; 7 `uvm_component_utils(test_base) 8 //virtual router_io router_vif,reset_vif; 9 router_env env; 10 //top_reset_sequencer top_reset_sqr; //(virtual sequencer) 11 function new(string name, uvm_component parent); 12 super.new(name, parent); 13 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 14 endfunction 15 16 virtual function void build_phase(uvm_phase phase); 17 super.build_phase(phase); 18 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 19 env = router_env::type_id::create("env", this); 20 21 // Lab 5 - Task 4, Step 6 22 // 23 // In the environment, the input agent has changed from a single instance to an array of 16 24 // agents. Within the test, the corresponding change also must take place. 25 // 26 // Change the configuration for the input agent objects to the following: 27 // 28 // uvm_config_db#(virtual router_io)::set(this, "env.i_agent[*]", "router_io", router_test_top.sigs); 29 // 30 // ToDo 31 uvm_config_db#(virtual router_io)::set(this, "env.i_agent[*]", "router_io", router_test_top.sigs); 32 //top_reset_sqr=top_reset_sequencer::type_id::create("top_reset_sqr",this); 33 34 // Lab 5 - Task 7, Step 8 35 // 36 // In the environment, an array of output agent has been added. Each of these agents need to 37 // access the physical signal. Configure the agents as follows: 38 // 39 // uvm_config_db#(virtual router_io)::set(this, "env.o_agent[*]", "router_io", router_test_top.sigs); 40 // ToDo 41 uvm_config_db#(virtual router_io)::set(this, "env.o_agent[*]", "router_io", router_test_top.sigs); 42 //uvm_config_db#(uvm_object_wrapper)::set(this,"env.r_agt.sqr.reset_phase","default_sequence", null); 43 //uvm_config_db#(uvm_object_wrapper)::set(this,"top_reset_sqr.reset_phase","default_sequence",top_reset_sequence::get_type()); 44 uvm_config_db#(virtual router_io)::set(this, "env.r_agent", "router_io", router_test_top.sigs); 45 endfunction 46 47 //connect_phase中,为top_reset_sqr的sub-sequencer赋值,建立virtual sequencer与physical sequencer的联系; 48 /*virtual function void connect_phase(uvm_phase phase); 49 super.connect_phase(phase); 50 foreach(env.i_agt[i]) begin 51 top_reset_sqr.pkt_sqr.push_back(env.i_agt[i].sqr); 52 end 53 top_reset_sqr.r_sqr=env.r_agt.sqr; 54 endfunction*/ 55 virtual task shutdown_phase(uvm_phase phase); 56 super.shutdown_phase(phase); 57 phase.raise_objection(this); 58 env.sb.wait_for_done(); 59 phase.drop_objection(this); 60 endtask: shutdown_phase 61 62 /* virtual task main_phase(uvm_phase phase); 63 uvm_objection objection; 64 super.main_phase(phase); 65 objection=phase.get_objection(); 66 objection.set_drain_time(this,1us); 67 endtask */ 68 69 virtual function void final_phase(uvm_phase phase); 70 super.final_phase(phase); 71 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 72 uvm_top.print_topology(); 73 uvm_factory::get().print(); 74 endfunction 75 endclass 76 77 78 `include "packet_da_3.sv" 79 80 class test_da_3_inst extends test_base; 81 `uvm_component_utils(test_da_3_inst) 82 83 function new(string name, uvm_component parent); 84 super.new(name, parent); 85 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 86 endfunction 87 88 virtual function void build_phase(uvm_phase phase); 89 super.build_phase(phase); 90 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 91 set_inst_override_by_type("env.i_agent*.seqr.*", packet::get_type(), packet_da_3::get_type()); 92 endfunction 93 endclass 94 95 class test_da_3_type extends test_base; 96 `uvm_component_utils(test_da_3_type) 97 98 function new(string name, uvm_component parent); 99 super.new(name, parent); 100 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 101 endfunction 102 103 virtual function void build_phase(uvm_phase phase); 104 super.build_phase(phase); 105 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 106 set_type_override_by_type(packet::get_type(), packet_da_3::get_type()); 107 endfunction 108 endclass 109 110 class test_da_3_seq extends test_base; 111 `uvm_component_utils(test_da_3_seq) 112 113 function new(string name, uvm_component parent); 114 super.new(name, parent); 115 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 116 endfunction 117 118 virtual function void build_phase(uvm_phase phase); 119 super.build_phase(phase); 120 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 121 uvm_config_db#(bit[15:0])::set(this, "env.i_agent*.seqr", "da_enable", 16'h0008); 122 uvm_config_db#(int)::set(this, "env.i_agent*.seqr", "item_count", 20); 123 endfunction 124 endclass 125 126 `endif
3.router_env.sv(派生于uvm_env)
注1:注意该段code中出现多个uvm_analysis_port连向同一个uvm_analysis_imp的情况;
1 `ifndef ROUTER_ENV__SV 2 `define ROUTER_ENV__SV 3 4 `include "input_agent.sv" 5 `include "reset_agent.sv" 6 7 // Lab 5 - Task 7, Step 2 8 // 9 // Include the scoreboard.sv and output_agent.sv files 10 // 11 // ToDo 12 //`include "scoreboard.sv" 13 `include "output_agent.sv" 14 15 16 // Lab 5 - Task 8, step 8 17 // 18 // Comment out the include statement above for the scoreboard.sv. 19 // Replace it with an include statement for ms_scoreboard.sv 20 // 21 // ToDo 22 `include "ms_scoreboard.sv" 23 24 25 class router_env extends uvm_env; 26 27 // Lab 5 - Task 4, Step 2 28 // 29 // The environment need 16 individual input agents. One for each DUT port. 30 // 31 // Change the following single instance of agent into an array of 16 agents: i_agent[16]. 32 // 33 // ToDo 34 input_agent i_agent[16]; 35 36 37 38 // Lab 5 - Task 7, Step 3 39 // 40 // Create an instance of scoreboard, call it sb. 41 // Create an array of output_agent, call it o_agent[16]. 42 // 43 // If you examine the output_agent code, you will find that the output_agent only contains 44 // an instance of oMonitor. This is because for the sake of lab simplicity, the DUT output 45 // protocal was designed without the need of a responder (push mode). Even though there are 46 // no sequencer nor drivers in the output agent, the output agent should still be created and 47 // instantiated in the environment. For flexibility of environment maintenance, this will be 48 // better in the longer run for unanticipated changes. 49 // 50 // ToDo 51 scoreboard sb; 52 output_agent o_agent[16]; 53 54 55 reset_agent r_agent; 56 57 `uvm_component_utils(router_env) 58 59 function new(string name, uvm_component parent); 60 super.new(name, parent); 61 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 62 endfunction 63 64 virtual function void build_phase(uvm_phase phase); 65 super.build_phase(phase); 66 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 67 68 // Lab 5 - Task 4, Step 3 69 // 70 // Change the following construction and configuration of a single instance of input agent into 71 // construction and configuration of all agents in the agent array. 72 // 73 // First, construct each input agent via the factory create() method. 74 // Then, for each agent, assign it to a dedicated port by setting the port_id field. 75 // Finally, for each agent, set the sequencer's default_sequence to packet_sequence. 76 // 77 // foreach (i_agent[i]) begin 78 // i_agent[i] = input_agent::type_id::create($sformatf("i_agent[%0d]", i), this); 79 // uvm_config_db #(int)::set(this, i_agent[i].get_name(), "port_id", i); 80 // uvm_config_db #(uvm_object_wrapper)::set(this, {i_agent[i].get_name(), ".", "seqr.main_phase"}, "default_sequence", packet_sequence::get_type()); 81 // end 82 // 83 // ToDo 84 foreach (i_agent[i]) begin 85 i_agent[i] = input_agent::type_id::create($sformatf("i_agent[%0d]", i), this); 86 uvm_config_db #(int)::set(this, i_agent[i].get_name(), "port_id", i); //采用get_name()函数,非常好; 87 uvm_config_db #(uvm_object_wrapper)::set(this, {i_agent[i].get_name(), ".", "seqr.main_phase"}, "default_sequence", packet_sequence::get_type()); 88 //uvm_config_db #(uvm_object_wrapper)::set(this,{i_agent[i].get_name(),".", "seqr.reset_phase"},"default_sequence", router_input_port_reset_sequence::get_type()); 89 end 90 91 // Lab 5 - Task 7, Step 4 92 // 93 // Construct the scoreboard and the output_agent objects with factory create() method. 94 // 95 // For each output_agent object, also configure its port_id field to a designated port. 96 // 97 // foreach (o_agent[i]) begin 98 // o_agent[i] = output_agent::type_id::create($sformatf("o_agent[%0d]", i), this); 99 // uvm_config_db #(int)::set(this, o_agent[i].get_name(), "port_id", i); 100 // end 101 // 102 // ToDo 103 sb = scoreboard::type_id::create("sb", this); 104 foreach (o_agent[i]) begin 105 o_agent[i] = output_agent::type_id::create($sformatf("o_agent[%0d]",i),this); 106 uvm_config_db #(int)::set(this, o_agent[i].get_name(), "port_id", i); 107 end 108 109 110 r_agent = reset_agent::type_id::create("r_agent", this); 111 uvm_config_db #(uvm_object_wrapper)::set(this, "r_agent.seqr.reset_phase", "default_sequence", reset_sequence::get_type()); 112 endfunction 113 114 virtual function void connect_phase(uvm_phase phase); 115 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 116 117 // Lab 5 - Task 7, Step 5 118 // 119 // Connect the scoreboard's before and after TLM exports to each agent's TLM analysis port. 120 // 121 // ToDo 122 foreach (i_agent[i]) begin 123 i_agent[i].analysis_port.connect(sb.before_export); //比较少使用,多个analysis_ap连向同一个imp; 124 end 125 foreach (o_agent[i]) begin 126 o_agent[i].analysis_port.connect(sb.after_export); 127 end 128 129 130 endfunction 131 132 endclass 133 134 `endif
4.input_agent.sv(派生于uvm_agent)
1 `ifndef INPUT_AGENT__SV 2 `define INPUT_AGENT__SV 3 4 // The files content needed by the agent must be included 5 `include "packet_sequence.sv" 6 `include "driver.sv" 7 8 // Lab 5 - Task 3, Step 2 9 // include the iMonitor.sv file 10 // 11 // ToDo 12 `include "iMonitor.sv" 13 14 15 typedef uvm_sequencer #(packet) packet_sequencer; 16 17 class input_agent extends uvm_agent; 18 // The input agent already contains the following properties from the previous lab: 19 virtual router_io sigs; // DUT virtual interface 20 int port_id = -1; // Agent's designated port 21 packet_sequencer seqr; 22 driver drv; 23 24 // Lab 5 - Task 3, Step 3 25 // Add an instance of iMonitor. Call it mon. 26 // And an instance of uvm_analysis_port #(packet). Call it analysis_port. 27 // 28 // This analysis port is just a pass-through port for the iMonitor's analysis port 29 // for the convinience of connection at the environment level. 30 // 31 // ToDo 32 iMonitor mon; 33 uvm_analysis_port #(packet) analysis_port; 34 35 36 `uvm_component_utils_begin(input_agent) 37 `uvm_field_int(port_id, UVM_DEFAULT | UVM_DEC) 38 `uvm_component_utils_end 39 40 function new(string name, uvm_component parent); 41 super.new(name, parent); 42 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 43 endfunction 44 45 virtual function void build_phase(uvm_phase phase); 46 super.build_phase(phase); 47 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 48 49 // The agent retrieves port_id and virtual interface. 50 uvm_config_db#(int)::get(this, "", "port_id", port_id); 51 uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs); 52 53 // Lab 5 - Task 3, Step 4 54 // 55 // Change the following construction and configure statements to obey the requirements 56 // of the is_active flag. 57 // 58 // Check the state of the is_active flag. If the is_active flag is UVM_ACTIVE, 59 // use the existing statements to construct and configure the sequencer and driver objects. 60 // 61 // ToDo 62 if (is_active == UVM_ACTIVE) begin 63 seqr = packet_sequencer::type_id::create("seqr", this); 64 drv = driver::type_id::create("drv", this); 65 66 uvm_config_db#(int)::set(this, "drv", "port_id", port_id); 67 uvm_config_db#(int)::set(this, "seqr", "port_id", port_id); 68 uvm_config_db#(virtual router_io)::set(this, "drv", "router_io", sigs); 69 uvm_config_db#(virtual router_io)::set(this, "seqr", "router_io", sigs); 70 end 71 72 73 // Lab 5 - Task 3, Step 5 74 // 75 // Regardless of the state of the is_active flag, construct and configure the iMonitor (mon) 76 // object. 77 // 78 // ToDo 79 mon = iMonitor::type_id::create("mon", this); 80 uvm_config_db#(int)::set(this, "mon", "port_id", port_id); 81 uvm_config_db#(virtual router_io)::set(this, "mon", "router_io", sigs); 82 83 84 endfunction 85 86 virtual function void connect_phase(uvm_phase phase); 87 super.connect_phase(phase); 88 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 89 90 // Lab 5 - Task 3, Step 6 91 // Change the following connect statement to obey the requirement of the is_active flag. 92 // 93 // If the is_active flag is UVM_ACTIVE, connect drv's seq_item_port to seqr's seq_item_export 94 // 95 // ToDo 96 if (is_active == UVM_ACTIVE) begin 97 drv.seq_item_port.connect(seqr.seq_item_export); 98 end 99 100 101 // Lab 5 - Task 3, Step 7 102 // Set the agent's pass-through analyais port (analysis_port) to reference the analysis port 103 // in iMonitor (mon). 104 // 105 // ToDo 106 this.analysis_port = mon.analysis_port; 107 108 109 endfunction 110 111 virtual function void start_of_simulation_phase(uvm_phase phase); 112 super.start_of_simulation_phase(phase); 113 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 114 `uvm_info("AGNTCFG", $sformatf("Using port_id of %0d", port_id), UVM_MEDIUM); 115 endfunction: start_of_simulation_phase 116 117 endclass 118 119 `endif
4.1 driver.sv
1 `ifndef DRIVER__SV 2 `define DRIVER__SV 3 4 class driver extends uvm_driver #(packet); 5 // Lab 4 - Task 2, Step 2 and 3 6 // Create the new fields as shown below. 7 // 8 // virtual router_io sigs; // DUT virtual interface 9 // int port_id = -1; // Driver's designated port 10 // 11 // The intent of the port_id field is to designate the driver for driving a specific port. 12 // 13 // If port_id is set in the range of 0 through 15, the driver will only drive 14 // the packet it gets from the sequencer through the DUT if the port_id matches the 15 // packet's source address (sa) field. If not, the packet is dropped. 16 // 17 // If port_id is -1 (the default), the driver will drive all packets it gets from 18 // the sequencer through the DUT without checking the packet's source address. 19 // 20 // Example: If port_id is 3 and req.sa is also 3, 21 // (req is the packet handle that sequencer passed to the driver) 22 // The driver will drive the packet through port 3 of DUT: sigs.drvClk.din[req.sa]; 23 // 24 // Example: If port_id is 3 and req.sa is 7, 25 // The driver will drop the packet. 26 // 27 // Example: If port_id is -1 and req.sa is 7, 28 // The driver will drive the packet through port 7 of DUT: sigs.drvClk.din[req.sa]; 29 // 30 // ToDo 31 virtual router_io sigs; // DUT virtual interface 32 int port_id = -1; // Driver's designated port 33 34 35 // Lab 4 - Task 2, Step 4 36 // 37 // Embed the port_id field in the `uvm_component_utils macro. 38 // Note: You will need to change the macro to `uvm_component_utils_begin 39 // with a corresponding `uvm_component_utils_end 40 // 41 // ToDo 42 `uvm_component_utils_begin(driver) 43 `uvm_field_int(port_id, UVM_DEFAULT | UVM_DEC) 44 `uvm_component_utils_end 45 46 47 function new(string name, uvm_component parent); 48 super.new(name, parent); 49 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 50 endfunction: new 51 52 53 function void build_phase(uvm_phase phase); 54 super.build_phase(phase); 55 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 56 57 // Lab 4 - Task 2, Step 5 58 // 59 // Retrieve the port_id configuration and the virtual interface. 60 // 61 // uvm_config_db#(int)::get(this, "", "port_id", port_id); 62 // if (!(port_id inside {-1, [0:15]})) begin 63 // `uvm_fatal("CFGERR", $sformatf("port_id must be {-1, [0:15]}, not %0d!", port_id)); 64 // end 65 // uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs); 66 // if (sigs == null) begin 67 // `uvm_fatal("CFGERR", "Interface for Driver not set"); 68 // end 69 // 70 // ToDo 71 uvm_config_db#(int)::get(this, "", "port_id", port_id); 72 if (!(port_id inside {-1, [0:15]})) begin 73 `uvm_fatal("CFGERR", $sformatf("port_id must be {-1, [0:15]}, not %0d!", port_id)); 74 end 75 uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs); 76 if (sigs == null) begin 77 `uvm_fatal("CFGERR", "Interface for Driver not set"); 78 end 79 80 81 endfunction: build_phase 82 83 84 // 85 // The UVM start_of_simulation phase is designed for displaying the testbench configuration 86 // before any active verification operation starts. 87 // 88 // For the sake of lab time, the start_of_simulation method is done for you. 89 // 90 virtual function void start_of_simulation_phase(uvm_phase phase); 91 super.start_of_simulation_phase(phase); 92 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 93 `uvm_info("DRV_CFG", $sformatf("port_id is: %0d", port_id), UVM_MEDIUM); 94 endfunction: start_of_simulation_phase 95 96 97 virtual task run_phase(uvm_phase phase); 98 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 99 100 forever begin 101 seq_item_port.get_next_item(req); 102 103 // Lab 4 - Task 2, Step 6 104 // 105 // Check port_id to see if the driver should accept or drop the packet. 106 // If port_id is -1, or if port_id matches req object's sa field, 107 // call send() method to drive the content of the req object through the DUT. 108 // Otherwise, drop the req object without processing. Like the following: 109 // 110 // if (port_id inside { -1, req.sa }) begin 111 // send(req); 112 // `uvm_info("DRV_RUN", {"\n", req.sprint()}, UVM_MEDIUM); 113 // end 114 // 115 // ToDo 116 if (port_id inside { -1, req.sa }) begin 117 send(req); 118 `uvm_info("DRV_RUN", {"\n", req.sprint()}, UVM_MEDIUM); 119 end 120 121 122 seq_item_port.item_done(); 123 end 124 endtask: run_phase 125 126 127 // Lab 4 - Task 8, Step 3 128 // 129 // The driver is fully responsible for asserting and de-asserting the signal set 130 // that it is assigned to handle. This includes setting the signal state at reset. 131 // 132 // At the pre_reset phase, the signals should be set to default values (x for logic, 133 // z for wire) to emulate power-up condition. 134 // 135 // At the reset phase, the signals should be set to the de-asserted states. 136 // 137 // These two methods are done for you. 138 // 139 // Caution: for this lab, we are not using the port_id because this lab is still 140 // just a part of initial bringup process. There is only one agent in the 141 // environment. So, if port_id is -1 (not using port_id), then the reset phases 142 // will initialized the signals for all router (DUT) ports. In the next lab, 143 // when you implement a dedicated agent for each port, the port_id will be set 144 // and the reset phases will only initialize its designated port. 145 // 146 // For this lab, just un-comment both the pre_reset and reset phase code. 147 // 148 // ToDo 149 150 virtual task pre_reset_phase(uvm_phase phase); 151 super.pre_reset_phase(phase); 152 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 153 phase.raise_objection(this); 154 if (port_id == -1) begin 155 sigs.drvClk.frame_n <= 'x; 156 sigs.drvClk.valid_n <= 'x; 157 sigs.drvClk.din <= 'x; 158 end else begin 159 sigs.drvClk.frame_n[port_id] <= 'x; 160 sigs.drvClk.valid_n[port_id] <= 'x; 161 sigs.drvClk.din[port_id] <= 'x; 162 end 163 phase.drop_objection(this); 164 endtask: pre_reset_phase 165 166 virtual task reset_phase(uvm_phase phase); 167 super.reset_phase(phase); 168 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 169 phase.raise_objection(this); 170 if (port_id == -1) begin 171 sigs.drvClk.frame_n <= '1; 172 sigs.drvClk.valid_n <= '1; 173 sigs.drvClk.din <= '0; 174 end else begin 175 sigs.drvClk.frame_n[port_id] <= '1; 176 sigs.drvClk.valid_n[port_id] <= '1; 177 sigs.drvClk.din[port_id] <= '0; 178 end 179 phase.drop_objection(this); 180 endtask: reset_phase 181 182 // 183 // In the interest of lab time, all device drivers have been done for you: 184 // 185 186 virtual task send(packet tr); 187 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 188 send_address(tr); 189 send_pad(tr); 190 send_payload(tr); 191 endtask: send 192 193 virtual task send_address(packet tr); 194 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 195 sigs.drvClk.frame_n[tr.sa] <= 1'b0; 196 for(int i=0; i<4; i++) begin 197 sigs.drvClk.din[tr.sa] <= tr.da[i]; 198 @(sigs.drvClk); 199 end 200 endtask: send_address 201 202 virtual task send_pad(packet tr); 203 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 204 sigs.drvClk.din[tr.sa] <= 1'b1; 205 sigs.drvClk.valid_n[tr.sa] <= 1'b1; 206 repeat(5) @(sigs.drvClk); 207 endtask: send_pad 208 209 virtual task send_payload(packet tr); 210 logic [7:0] datum; 211 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 212 while(!sigs.drvClk.busy_n[tr.sa]) @(sigs.drvClk); 213 foreach(tr.payload[index]) begin 214 datum = tr.payload[index]; 215 for(int i=0; i<$size(tr.payload, 2); i++) begin 216 sigs.drvClk.din[tr.sa] <= datum[i]; 217 sigs.drvClk.valid_n[tr.sa] <= 1'b0; 218 sigs.drvClk.frame_n[tr.sa] <= ((tr.payload.size()-1) == index) && (i==7); 219 @(sigs.drvClk); 220 end 221 end 222 sigs.drvClk.valid_n[tr.sa] <= 1'b1; 223 endtask: send_payload 224 225 endclass: driver 226 227 `endif
4.2 iMonitor.sv
1 `ifndef IMONITOR__SV 2 `define IMONITOR__SV 3 4 class iMonitor extends uvm_monitor; 5 // Just like in the driver, the monitors will need a port designater variable 6 // and access to DUT virtual interface. They are exactly the same as driver. 7 // There are no additional learning points in creating and configuring these 8 // fields, so they are done for you. 9 virtual router_io sigs; 10 int port_id = -1; 11 12 13 // Lab 5 - Task 2, Step 2 14 // Create a TLM analysis port typed to packet. Call the handle analysis_port. 15 // 16 // ToDo 17 uvm_analysis_port #(packet) analysis_port; 18 19 `uvm_component_utils_begin(iMonitor) 20 `uvm_field_int(port_id, UVM_DEFAULT | UVM_DEC) 21 `uvm_component_utils_end 22 23 function new(string name, uvm_component parent); 24 super.new(name, parent); 25 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 26 endfunction 27 28 function void build_phase(uvm_phase phase); 29 super.build_phase(phase); 30 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 31 if (!uvm_config_db#(int)::get(this, "", "port_id", port_id)) begin 32 `uvm_fatal("CFGERR", "iMonitor port_id not set"); 33 end 34 if (!uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs)) begin 35 `uvm_fatal("CFGERR", "iMonitor DUT interface not set"); 36 end 37 38 // Lab 5 - Task 2, Step 3 39 // Construct analysis_port. 40 // 41 // TLM ports in UVM do not have factory support. You cannot construct 42 // TLM ports with the factory create() method. 43 // You can only construct TLM ports by calling its constructor. 44 // 45 // ToDo 46 analysis_port = new("analysis_port", this); 47 48 endfunction 49 50 virtual task run_phase(uvm_phase phase); 51 52 // The job of the monitor is to passively monitor the physical signals, 53 // interprete and report the activities that it sees. In this case, to 54 // re-construct the packet that it sees on the DUT's input port as specified 55 // by port_id. 56 // 57 // The observed packet need to be stored in an object. In this task, that 58 // object handle is tr as declared below. 59 60 packet tr; 61 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 62 63 forever begin 64 65 // Lab 5 - Task 2, Step 5 66 // Within the forever loop, you need to construct the object (tr) in which the 67 // observed transaction on the DUT input port can be stored. As always, use the 68 // factory create() method to do the construction. 69 // 70 // In the observed transaction object, there are three fields that needs to be 71 // populated: source address (sa), destination address (da) and the payload array 72 // (payload). 73 // 74 // The source address is not part of the observable bit stream on the DUT interface. 75 // It is, by definition, the port_id of the iMonitor object. You should set this 76 // field before calling the device driver (get_packet). 77 // 78 // Both the destination address and the payload can be extracted from the obserable 79 // bit stream on the DUT interface. These will be populated by the device driver. 80 // 81 // After setting the source address field, call get_packet() to retrieve the observed 82 // transaction. Then, display the content of the observed transaction and pass the 83 // observed transaction on to all other interested component via the TLM analysis port 84 // (analysis_port) by calling its write() method. 85 // 86 // tr = packet::type_id::create("tr", this); 87 // tr.sa = this.port_id; 88 // get_packet(tr); 89 // `uvm_info("Got Input Packet", {"\n", tr.sprint()}, UVM_MEDIUM); 90 // analysis_port.write(tr); 91 // 92 // ToDo 93 tr = packet::type_id::create("tr", this); 94 tr.sa = this.port_id; 95 get_packet(tr); 96 `uvm_info("Got Input Packet", {"\n", tr.sprint()}, UVM_MEDIUM); 97 analysis_port.write(tr); 98 99 100 end 101 endtask 102 103 // 104 // In the interest of lab time, the device driver code is done for you. 105 // 106 107 virtual task get_packet(packet tr); 108 logic [7:0] datum; 109 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 110 @(negedge sigs.iMonClk.frame_n[port_id]); 111 112 for (int i=0; i<4; i++) begin 113 if (!sigs.iMonClk.frame_n[port_id]) begin 114 tr.da[i] = sigs.iMonClk.din[port_id]; 115 end else begin 116 `uvm_fatal("Header Error", $sformatf("@ Header cycle %0d, Frame not zero", i)); 117 end 118 @(sigs.iMonClk); 119 end 120 121 for (int i=0; i<5; i++) begin 122 if (!sigs.iMonClk.frame_n[port_id]) begin 123 if (sigs.iMonClk.valid_n[port_id] && sigs.iMonClk.din[port_id]) begin 124 @(sigs.iMonClk); 125 continue; 126 end else begin 127 `uvm_fatal("Header Error", $sformatf("@%0d Valid or Din zero", i)); 128 end 129 end else begin 130 `uvm_fatal("Header Error", "Frame not zero"); 131 end 132 end 133 134 forever begin 135 for(int i=0; i<8; i=i) begin 136 if (!sigs.iMonClk.valid_n[port_id]) begin 137 if (sigs.iMonClk.busy_n[port_id]) begin 138 datum[i++] = sigs.iMonClk.din[port_id]; 139 if (i == 8) begin 140 tr.payload.push_back(datum); 141 end 142 end else begin 143 `uvm_fatal("Payload Error", "Busy & Valid conflict"); 144 end 145 end 146 if (sigs.iMonClk.frame_n[port_id]) begin 147 if (i == 8) begin 148 return; 149 end else begin 150 `uvm_fatal("Payload Error", "Not byte aligned"); 151 end 152 end 153 @(sigs.iMonClk); 154 end 155 end 156 endtask: get_packet 157 158 endclass 159 160 `endif
5.output_agent.sv
1 `ifndef OUTPUT_AGENT__SV 2 `define OUTPUT_AGENT__SV 3 4 // include the oMonitor.sv file 5 `include "oMonitor.sv" 6 7 class output_agent extends uvm_agent; 8 // This output agent does not have seqeuncer and driver, but still require a monitor 9 // and the associated port_id,virtual interface and analysis port. 10 virtual router_io sigs; // DUT virtual interface 11 int port_id = -1; // Agent's designated port 12 oMonitor mon; 13 uvm_analysis_port #(packet) analysis_port; 14 15 `uvm_component_utils_begin(output_agent) 16 `uvm_field_int(port_id, UVM_DEFAULT | UVM_DEC) 17 `uvm_component_utils_end 18 19 function new(string name, uvm_component parent); 20 super.new(name, parent); 21 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 22 endfunction 23 24 virtual function void build_phase(uvm_phase phase); 25 super.build_phase(phase); 26 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 27 28 // The agent retrieves port_id and virtual interface. 29 uvm_config_db#(int)::get(this, "", "port_id", port_id); 30 uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs); 31 32 mon = oMonitor::type_id::create("mon", this); 33 uvm_config_db#(int)::set(this, "mon", "port_id", port_id); 34 uvm_config_db#(virtual router_io)::set(this, "mon", "router_io", sigs); 35 endfunction 36 37 virtual function void connect_phase(uvm_phase phase); 38 super.connect_phase(phase); 39 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 40 41 this.analysis_port = mon.analysis_port; 42 endfunction 43 44 virtual function void start_of_simulation_phase(uvm_phase phase); 45 super.start_of_simulation_phase(phase); 46 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 47 `uvm_info("AGNTCFG", $sformatf("Using port_id of %0d", port_id), UVM_MEDIUM); 48 endfunction: start_of_simulation_phase 49 50 endclass 51 52 `endif
5.1oMonitor.sv
1 `ifndef OMONITOR__SV 2 `define OMONITOR__SV 3 4 class oMonitor extends uvm_monitor; 5 int port_id = -1; 6 virtual router_io sigs; 7 uvm_analysis_port #(packet) analysis_port; 8 9 `uvm_component_utils_begin(oMonitor) 10 `uvm_field_int(port_id, UVM_DEFAULT | UVM_DEC) 11 `uvm_component_utils_end 12 13 function new(string name, uvm_component parent); 14 super.new(name, parent); 15 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 16 endfunction 17 18 function void build_phase(uvm_phase phase); 19 super.build_phase(phase); 20 if (!uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs)) begin 21 `uvm_fatal("CFGERR", "oMonitor DUT interface not set"); 22 end 23 analysis_port = new("analysis_port", this); 24 endfunction 25 26 virtual task run_phase(uvm_phase phase); 27 packet tr; 28 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 29 forever begin 30 tr = packet::type_id::create("tr", this); 31 tr.da = this.port_id; 32 this.get_packet(tr); 33 `uvm_info("Got Output Packet", {"\n", tr.sprint()}, UVM_MEDIUM); 34 analysis_port.write(tr); 35 end 36 endtask 37 38 task get_packet(packet tr); 39 logic [7:0] datum; 40 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 41 @(negedge sigs.oMonClk.frameo_n[port_id]); 42 43 forever begin 44 for(int i=0; i<8; i=i) begin 45 if (!sigs.oMonClk.valido_n[port_id]) begin 46 datum[i++] = sigs.oMonClk.dout[port_id]; 47 if (i == 8) begin 48 tr.payload.push_back(datum); 49 end 50 if (sigs.oMonClk.frameo_n[port_id]) begin 51 if (i == 8) begin 52 return; 53 end else begin 54 `uvm_fatal("Payload Error", "Not byte aligned"); 55 end 56 end 57 end 58 @(sigs.oMonClk); 59 end 60 end 61 endtask: get_packet 62 63 endclass 64 65 `endif
6.ms_scoreboard.sv(ms-multi_stream)
注1:uvm_in_order_class_comparator的使用;
1 `ifndef SCOREBOARD__SV 2 `define SCOREBOARD__SV 3 4 `uvm_analysis_imp_decl(_before) 5 `uvm_analysis_imp_decl(_after) 6 7 class scoreboard extends uvm_scoreboard; 8 uvm_analysis_imp_before #(packet, scoreboard) before_export; 9 uvm_analysis_imp_after #(packet, scoreboard) after_export; 10 uvm_in_order_class_comparator #(packet) comparator[16]; 11 //int count=0; 12 //realtime timeout = 10us; 13 `uvm_component_utils(scoreboard) 14 15 function new(string name, uvm_component parent); 16 super.new(name, parent); 17 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 18 endfunction 19 20 virtual function void build_phase(uvm_phase phase); 21 super.build_phase(phase); 22 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 23 before_export = new("before_export", this); 24 after_export = new("after_export", this); 25 for (int i=0; i < 16; i++) begin 26 comparator[i] = uvm_in_order_class_comparator #(packet)::type_id::create($sformatf("comparator_%0d", i), this); 27 end 28 endfunction 29 30 virtual function void write_before(packet pkt); 31 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 32 comparator[pkt.da].before_export.write(pkt); 33 //count++; 34 endfunction 35 36 virtual function void write_after(packet pkt); 37 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 38 comparator[pkt.da].after_export.write(pkt); 39 //count--; 40 endfunction 41 42 /* virtual task wait_for_done(); 43 fork 44 begin 45 fork 46 wait(count==0); 47 begin 48 #timeout; 49 end 50 join_any; 51 disable fork; 52 end 53 join 54 endtask: wait_for_done */ 55 56 virtual function void report(); 57 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 58 foreach (comparator[i]) begin 59 `uvm_info("Scoreboard Report", 60 $sformatf("Comparator[%0d] Matches = %0d, Mismatches = %0d", 61 i, comparator[i].m_matches, comparator[i].m_mismatches), UVM_MEDIUM); 62 end 63 endfunction 64 65 endclass 66 67 `endif
7.scoreboard.sv(not used)
1 `ifndef SCOREBOARD__SV 2 `define SCOREBOARD__SV 3 4 class scoreboard extends uvm_scoreboard; 5 6 // Lab 5 - Task 6, Step 2 7 // 8 // Add an instance of uvm_in_order_class_comparator typed to packet. Call it comparator. 9 // 10 // ToDo 11 uvm_in_order_class_comparator #(packet) comparator; 12 13 14 // Lab 5 - Task 6, Step 3 15 // 16 // Create two uvm_analysis_export, one called before_export and the other after_export. 17 // 18 // ToDo 19 uvm_analysis_export #(packet) before_export; 20 uvm_analysis_export #(packet) after_export; 21 22 23 `uvm_component_utils(scoreboard) 24 25 function new(string name, uvm_component parent); 26 super.new(name, parent); 27 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 28 endfunction 29 30 virtual function void build_phase(uvm_phase phase); 31 super.build_phase(phase); 32 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 33 //before_export=new("before_export",this); after_export=new("after_export",this); 34 // Lab 5 - Task 6, Step 4 35 // 36 // Construct the comparator. 37 // Set the two analysis exports to the corresponding exports in the comparators. 38 // 39 // ToDo 40 comparator = uvm_in_order_class_comparator #(packet)::type_id::create("comparator", this); 41 before_export = comparator.before_export; 42 after_export = comparator.after_export; 43 //this.before_export.connect(comparator.before_export); 44 //this.after_export.connect(comparator.after_export); 45 endfunction 46 47 // 48 // You should always print the comparison results in the report phase/ 49 // This is done for you. 50 // 51 virtual function void report_phase(uvm_phase phase); 52 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 53 `uvm_info("Scoreboard Report", 54 $sformatf("Comparator Matches = %0d, Mismatches = %0d", comparator.m_matches, comparator.m_mismatches), UVM_MEDIUM); 55 endfunction 56 57 endclass 58 59 `endif
8.reset_agent.sv(reset_driver, reset_monitor, reset_sequencer)
(1)注意reset_monitor内uvm_event的使用;
1 `ifndef RESET_AGENT__SV 2 `define RESET_AGENT__SV 3 4 `include "reset_sequence.sv" 5 6 typedef class reset_driver; 7 typedef class reset_monitor; 8 typedef uvm_sequencer#(reset_tr) reset_sequencer; 9 10 class reset_agent extends uvm_agent; 11 virtual router_io sigs; // DUT virtual interface 12 reset_sequencer seqr; 13 reset_driver drv; 14 reset_monitor mon; 15 16 `uvm_component_utils(reset_agent) 17 18 function new(string name, uvm_component parent); 19 super.new(name, parent); 20 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 21 endfunction: new 22 23 function void build_phase(uvm_phase phase); 24 super.build_phase(phase); 25 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 26 27 uvm_config_db#(uvm_active_passive_enum)::get(this, "", "is_active", is_active); 28 `uvm_info("RSTCFG", $sformatf("Reset agent %s setting for is_active is: %p", this.get_name(), is_active), UVM_MEDIUM); 29 30 uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs); 31 32 if (is_active == UVM_ACTIVE) begin 33 seqr = reset_sequencer::type_id::create("seqr", this); 34 drv = reset_driver::type_id::create("drv", this); 35 uvm_config_db#(virtual router_io)::set(this, "drv", "router_io", sigs); 36 uvm_config_db#(virtual router_io)::set(this, "seqr", "router_io", sigs); 37 end 38 mon = reset_monitor::type_id::create("mon", this); 39 uvm_config_db#(virtual router_io)::set(this, "mon", "router_io", sigs); 40 endfunction: build_phase 41 42 virtual function void connect_phase(uvm_phase phase); 43 super.connect_phase(phase); 44 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 45 if (is_active == UVM_ACTIVE) begin 46 drv.seq_item_port.connect(seqr.seq_item_export); 47 end 48 endfunction: connect_phase 49 endclass 50 51 /* 52 class reset_tr extends uvm_sequence_item; 53 typedef enum {ASSERT, DEASSERT} kind_e; 54 rand kind_e kind; 55 rand int unsigned cycles = 1; 56 endclass 57 */ 58 59 class reset_driver extends uvm_driver #(reset_tr); 60 virtual router_io sigs; // DUT virtual interface 61 `uvm_component_utils(reset_driver) 62 63 function new(string name, uvm_component parent); 64 super.new(name, parent); 65 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 66 endfunction: new 67 68 function void build_phase(uvm_phase phase); 69 super.build_phase(phase); 70 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 71 72 if (!uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs)) begin 73 `uvm_fatal("CFGERR", "Interface for reset driver not set"); 74 end 75 endfunction: build_phase 76 77 virtual task run_phase(uvm_phase phase); 78 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 79 80 forever begin 81 seq_item_port.get_next_item(req); 82 drive(req); 83 seq_item_port.item_done(); 84 end 85 endtask: run_phase 86 87 virtual task drive(reset_tr tr); 88 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 89 if (tr.kind == reset_tr::ASSERT) begin 90 sigs.reset_n = 1'b0; 91 repeat(tr.cycles) @(sigs.drvClk); 92 end else begin 93 sigs.reset_n <= '1; 94 repeat(tr.cycles) @(sigs.drvClk); 95 end 96 endtask: drive 97 endclass 98 99 class reset_monitor extends uvm_monitor; 100 virtual router_io sigs; // DUT virtual interface 101 uvm_analysis_port #(reset_tr) analysis_port; 102 `uvm_component_utils(reset_monitor) 103 //uvm_event reset_event=uvm_event_pool::get_global("reset"); 104 function new(string name, uvm_component parent); 105 super.new(name, parent); 106 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 107 endfunction: new 108 109 function void build_phase(uvm_phase phase); 110 super.build_phase(phase); 111 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 112 113 if (!uvm_config_db#(virtual router_io)::get(this, "", "router_io", sigs)) begin 114 `uvm_fatal("CFGERR", "Interface for reset monitor not set"); 115 end 116 117 analysis_port = new("analysis_port", this); 118 endfunction: build_phase 119 120 virtual task run_phase(uvm_phase phase); 121 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 122 123 forever begin 124 reset_tr tr = reset_tr::type_id::create("tr", this); 125 detect(tr); 126 analysis_port.write(tr); 127 end 128 endtask: run_phase 129 130 virtual task detect(reset_tr tr); 131 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 132 @(sigs.reset_n); 133 assert(!$isunknown(sigs.reset_n)); 134 if (sigs.reset_n == 1'b0) begin 135 tr.kind = reset_tr::ASSERT; //reset_event.trigger(); 136 end else begin 137 tr.kind = reset_tr::DEASSERT; //reset_event.reset(.wakeup(1));为什么需要指定wakeup参数?? 138 end 139 endtask: detect 140 endclass 141 142 `endif
9.packet_sequence.sv
1 `ifndef PACKET_SEQUENCE__SV 2 `define PACKET_SEQUENCE__SV 3 4 `include "packet.sv" 5 6 class packet_sequence extends uvm_sequence #(packet); 7 int item_count = 10; 8 int port_id = -1; 9 bit[15:0] da_enable = '1; 10 int valid_da[$]; 11 12 `uvm_object_utils_begin(packet_sequence) 13 `uvm_field_int(item_count, UVM_ALL_ON) 14 `uvm_field_int(port_id, UVM_ALL_ON) 15 `uvm_field_int(da_enable, UVM_ALL_ON) 16 `uvm_field_queue_int(valid_da, UVM_ALL_ON) 17 `uvm_object_utils_end 18 19 function void pre_randomize(); 20 uvm_config_db#(int)::get(m_sequencer, "", "item_count", item_count); //m_sequencer或者get_sequencer(); 21 uvm_config_db#(int)::get(m_sequencer, "", "port_id", port_id); 22 uvm_config_db#(bit[15:0])::get(m_sequencer, "", "da_enable", da_enable); 23 if (!(port_id inside {-1, [0:15]})) begin 24 `uvm_fatal("CFGERR", $sformatf("Illegal port_id value of %0d", port_id)); 25 end 26 27 valid_da.delete(); 28 for (int i=0; i<16; i++) 29 if (da_enable[i]) 30 valid_da.push_back(i); 31 endfunction 32 33 function new(string name = "packet_sequence"); 34 super.new(name); 35 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 36 endfunction 37 38 virtual task body(); 39 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 40 uvm_config_db#(int)::get(m_sequencer, "*", "item_count", item_count); 41 42 if (starting_phase != null) begin 43 44 // Lab 5 - Task 8, Step 3 45 // Retrieve the objection handle for the phase. Then, set the drain time to 1us. 46 // 47 // uvm_objection objection = starting_phase.get_objection(); 48 // objection.set_drain_time(this, 1us); 49 // 50 // ToDo 51 uvm_objection objection = starting_phase.get_objection(); 52 objection.set_drain_time(this, 1us); 53 54 55 starting_phase.raise_objection(this); 56 end 57 58 repeat(item_count) begin 59 `uvm_do_with(req, {if (port_id == -1) sa inside {[0:15]}; else sa == port_id; da inside valid_da;}); 60 end 61 62 if (starting_phase != null) 63 starting_phase.drop_objection(this); 64 endtask 65 66 endclass 67 68 `endif
9.1packet.sv
1 `ifndef PACKET__SV 2 `define PACKET__SV 3 4 // Lab 1 - Declare the class packet that extends uvm_sequence_item 5 // 6 // ToDo 7 class packet extends uvm_sequence_item; 8 9 // Lab 1 - Declare the random 4-bit sa and da fields 10 // 11 // ToDo 12 rand bit [3:0] sa, da; 13 14 // Lab 1 - Declare the random 8-bit payload queue 15 // 16 // ToDo 17 rand bit[7:0] payload[$]; 18 19 `uvm_object_utils_begin(packet) 20 `uvm_field_int(sa, UVM_ALL_ON | UVM_NOCOMPARE) 21 `uvm_field_int(da, UVM_ALL_ON) 22 `uvm_field_queue_int(payload, UVM_ALL_ON) 23 `uvm_object_utils_end 24 25 constraint valid { 26 payload.size inside {[1:10]}; 27 } 28 29 // Lab 1 - Create the constructor with one argument: string name="packet" 30 // Lab 1 - Call super.new() with this argument 31 // Lab 1 - Lastly, print a message with: 32 // Lab 1 - `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 33 // 34 // ToDo 35 function new(string name = "packet"); 36 super.new(name); 37 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 38 endfunction: new 39 40 41 endclass: packet 42 `endif
9.2packet_da_3.sv
1 `ifndef PACKET_DA_3__SV 2 `define PACKET_DA_3__SV 3 4 class packet_da_3 extends packet; 5 `uvm_object_utils(packet_da_3) 6 7 // Lab 2 - set the constraint for destination address (da) to 3 8 // 9 // ToDo 10 constraint da_3 { 11 da == 3; 12 } 13 14 function new(string name = "packet_da_3"); 15 super.new(name); 16 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 17 endfunction 18 endclass 19 20 `endif
10.与reset相关的sequence
10.1reset_sequence.sv
1 `ifndef RESET_SEQUENCE__SV 2 `define RESET_SEQUENCE__SV 3 4 // Reset structure is done in the same way as all other UVM component structure. 5 // A reset agent contains a reset sequencer, driver and monitor. 6 // 7 // The reset sequencer executes a reset sequence (this file), and passes the reset 8 // transaction (reset_tr) to the reset driver. The reset driver then assert/de-assert 9 // the reset signal as specified in the reset transaction. 10 // 11 // Within the reset transaction class, there is a control command field called kind. 12 // If the kind field is ASSERT, then the driver will assert the reset signal for 13 // the number of clock cycles are specified in the cycles field. Similar action 14 // takes place for the DEASSERT command. 15 // 16 // For example, if the reset signal need to be asserted for 2 cycles then de-asserted 17 // for 15 clock cycles, the potential code might look like: 18 // 19 // reset_tr tr = reset_tr::type_id::create("tr"); 20 // tr.randomize() with {kind == ASSERT; cycles == 2;}; 21 // tr.randomize() with {kind == DEASSERT; cycles == 15;; 22 23 class reset_tr extends uvm_sequence_item; 24 typedef enum {ASSERT, DEASSERT} kind_e; 25 rand kind_e kind; 26 rand int unsigned cycles = 1; 27 28 `uvm_object_utils_begin(reset_tr) 29 `uvm_field_enum(kind_e, kind, UVM_ALL_ON) 30 `uvm_field_int(cycles, UVM_ALL_ON) 31 `uvm_object_utils_end 32 33 function new(string name = "reset_tr"); 34 super.new(name); 35 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 36 endfunction: new 37 endclass 38 39 class reset_sequence extends uvm_sequence #(reset_tr); 40 `uvm_object_utils(reset_sequence) 41 42 function new(string name = "reset_sequence"); 43 super.new(name); 44 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 45 endfunction 46 47 task body(); 48 `uvm_info("TRACE", $sformatf("%m"), UVM_HIGH); 49 50 if (starting_phase != null) 51 starting_phase.raise_objection(this); 52 53 // Lab 4 - Task 6, Step 2 54 // 55 // Enter the code to assert reset for 2 cycles, followed by de-assert of reset for 15 cycles. 56 // 57 // ToDo 58 `uvm_do_with(req, {kind == ASSERT; cycles == 2;}); 59 `uvm_do_with(req, {kind == DEASSERT; cycles == 15;}); 60 61 62 if (starting_phase != null) 63 starting_phase.drop_objection(this); 64 endtask 65 66 endclass 67 68 `endif
10.2 router_input_port_reset_sequence.sv
1 class router_input_port_reset_sequence extends uvm_sequence #(packet); 2 virtual router_io vif; 3 input port_id=-1; 4 5 `uvm_object_utils_begin(router_input_port_reset_sequence) 6 `uvm_field_int(port_id, UVM_DEFAULT | UVM_DEC) 7 `uvm_object_utils_end 8 9 function new(string name="router_input_port_reset_sequence"); 10 super.new(name); 11 `uvm_info("TRACE",$sformatf("%m"),UVM_HIGH) 12 `ifdef UVM_POST_VERSION_1_1 13 set_automatic_phase_objection(1); 14 `endif 15 endfunction 16 17 virtual task pre_start(); 18 `ifdef UVM_VERSION_1_1 19 if((get_parent_sequence()==null) && (starting_phase!=null)) begin 20 starting_phase.raise_objection(this); 21 end 22 `endif 23 24 uvm_config_db#(int)::get(get_sequencer(),"","port_id",port_id); 25 if(!(port_id inside {-1,[0:15]})) begin 26 `uvm_fatal("CFGERR",$sformatf("port_id must be {-1,[0:15]}, not %0d!",port_id)) 27 end 28 uvm_config_db#(virtual router_io)::get(get_sequencer(),"","vif",vif); 29 if(vif==null) begin 30 `uvm_fatal("CFGERR","Interface for the Driver Reset Sequence not set") 31 end 32 endtask: pre_start 33 34 `ifdef UVM_VERSION_1_1 35 virtual task post_start(); 36 if((get_parent_sequence()==null) && (starting_phase!=null)) begin 37 starting_phase.drop_objection(this); 38 end 39 endtask: post_start 40 `endif 41 42 virtual task body(); 43 if(port_id==-1) begin 44 vif.frame_n='1; 45 vif.valid_n='1; 46 vif.din='0; 47 end 48 else begin 49 vif.frame_n='1; 50 vif.valid_n='1; 51 vif.din='0; 52 end 53 endtask 54 endclass
11.top_reset_sequencer.sv & top_reset_sequence.sv
注1:使用了virtual sequencer和virtual sequence机制,在top_reset_sequence.sv内协调reset_sequence与router_input_port_reset_sequence的执行;
注2:在reset信号assert前,DUT的其他输入信号0时刻值应该是unknown的;
注3:如果每个agent的sequencer独立执行它们的reset sequence,那么就可能造成reset信号assert前,其他input信号不是unknown值;
1 class router_env extends uvm_env;
2 ...
3 virtual function void build_phase(uvm_phase phase);
4 super.build_phase(phase);
5 uvm_config_db#(uvm_object_wrapper)::set(this,"r_agt.sqr.reset_phase","default_sequence",reset_sequence::get_type());
6
7 foreach(i_agent[i]) begin
8 uvm_config_db#(uvm_object_wrapper)::set(this,{i_agent[i].get_name(),".sqr.reset_phase"},"default_sequence", router_input_port_reset_sequence::get_type());
9 end
10 endfunction
11 ...
12 endclass
注4:正确的处理方法是在reset assert前,其他输入信号应该置于它们的默认态(x for logic, z for wire);接着,检测到reset信号后,为这些信号设置合理的复位值;推荐使用top reset sequence(virtual sequence)和top reset sequencer(virtual sequencer);
11.1 top_reset_sequencer.sv
1 class top_reset_sequencer extends uvm_sequencer; 2 `uvm_component_utils(top_reset_sequencer) 3 typedef uvm_sequencer#(reset_tr) reset_sequencer; 4 typedef uvm_sequencer#(packet) packet_sequencer; 5 6 reset_sequencer r_sqr; 7 packet_sequencer pkt_sqr[$]; 8 9 function new(string name, uvm_component parent); 10 super.new(name,parent); 11 `uvm_info("TRACE",$sformatf("%m"),UVM_HIGH) 12 endfunction 13 endclass
11.2 top_reset_sequence.sv
1 class top_reset_sequence extends uvm_sequence; 2 `uvm_object_utils(top_reset_sequence) 3 `uvm_declare_p_sequencer(top_reset_sequencer) 4 5 reset_sequence r_seq; 6 router_input_port_reset_sequence i_seq; 7 uvm_event reset_event=uvm_event_pool::get_global("reset"); 8 9 function new(string name="top_reset_sequence"); 10 super.new(name); 11 `uvm_info("TRACE",$sformatf("%m"),UVM_HIGH) 12 `ifdef UVM_POST_VERSION_1_1 13 set_automatic_phase_objection(1); 14 `endif 15 endfunction 16 17 virtual task body(); 18 `uvm_info("TRACE",$sformatf("%m"),UVM_HIGH) 19 fork 20 `uvm_do_on(r_seq,p_sequencer.r_sqr); 21 foreach(p_sequencer.pkt_sqr[i]) begin 22 fork 23 int j=i; 24 begin 25 reset_event.wait_on();//该处采用了wait_on()而不是wait_trigger,与sequence和driver行为相关; 26 `uvm_do_on(i_seq,p_sequencer.pkt_sqr[j]); 27 end 28 join_none 29 end 30 join 31 endtask 32 33 `ifdef UVM_VERSION_1_1 34 virtual task pre_start(); 35 `uvm_info("TRACE",$sformatf("%m"),UVM_HIGH) 36 if((get_parent_sequence()==null) && (starting_phase!=null)) 37 starting_phase.raise_objection(this); 38 endtask 39 virtual task post_start(); 40 `uvm_info("TRACE",$sformatf("%m"),UVM_HIGH) 41 if((get_parent_sequence()==null) && (starting_phase!=null)) 42 starting_phase.raise_objection(this); 43 endtask 44 `endif 45 endclass