/ sim / test_lib.py
test_lib.py
  1  ##################################################################################################
  2  # BSD 3-Clause License
  3  #
  4  # Copyright (c) 2022, Jose R. Garcia
  5  # All rights reserved.
  6  #
  7  # Redistribution and use in source and binary forms, with or without
  8  # modification, are permitted provided that the following conditions are met:
  9  #
 10  # 1. Redistributions of source code must retain the above copyright notice, this
 11  #    list of conditions and the following disclaimer.
 12  #
 13  # 2. Redistributions in binary form must reproduce the above copyright notice,
 14  #    this list of conditions and the following disclaimer in the documentation
 15  #    and/or other materials provided with the distribution.
 16  #
 17  # 3. Neither the name of the copyright holder nor the names of its
 18  #    contributors may be used to endorse or promote products derived from
 19  #    this software without specific prior written permission.
 20  #
 21  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 22  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 23  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 24  # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 25  # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 26  # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 27  # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 29  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 30  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 31  #
 32  ##################################################################################################
 33  # File name    : test_lib.py
 34  # Author       : Jose R Garcia (jg-fossh@protonmail.com)
 35  # Project Name : Goldschmidt Integer Divider
 36  # Class Name   : test_lib
 37  # Description  : Collection of tests available for this module.
 38  #
 39  # Additional Comments:
 40  #   Contains the test base and tests.
 41  ##################################################################################################
 42  # Framework Libs
 43  import cocotb
 44  from cocotb.triggers import Timer
 45  # UVM Libs
 46  from uvm import *
 47  from wb4s_seq import *
 48  from wb4s_agent import *
 49  from wb4s_config import *
 50  from tb_env_config import *
 51  from tb_env import *
 52  from predictor import *
 53  # General Python Libs
 54  import math
 55  import random as rnd
 56  
 57  class test_base(UVMTest):
 58      """
 59         Class: Test Base
 60  
 61         Definition: Contains functions, tasks and methods.
 62      """
 63  
 64      def __init__(self, name="test_base", parent=None):
 65          super().__init__(name, parent)
 66          self.test_pass = True
 67          self.err_msg = ""
 68          self.tb_env = None
 69          self.tb_env_config = None
 70          self.wb4s_agent_cfg = None
 71          self.printer = None
 72  
 73      def build_phase(self, phase):
 74          super().build_phase(phase)
 75          # Enable transaction recording for everything
 76          UVMConfigDb.set(self, "*", "recording_detail", UVM_FULL)
 77  
 78          # create this test test bench environment config
 79          arr = []
 80          if UVMConfigDb.get(None, "dut", "DUT_SLAVE_DATA_IN_LENGTH", arr) is True:
 81              UVMConfigDb.set(None, "*", "DUT_SLAVE_DATA_IN_LENGTH", arr[0])
 82  
 83          self.tb_env_config = tb_env_config.type_id.create("tb_env_config", self)
 84          self.tb_env_config.has_scoreboard           = True
 85          self.tb_env_config.has_predictor            = True
 86          self.tb_env_config.has_functional_coverage  = False
 87          self.tb_env_config.DUT_SLAVE_DATA_IN_LENGTH = arr[0]
 88          self.tb_env_config.data_bins_range          = [0, 0xFFFFFFFF]
 89  
 90          # Create the Mem Read agent
 91          self.wb4s_agent_cfg = wb4s_config.type_id.create("wb4s_agent_cfg", self)
 92          arr = []
 93          # Get the instruction interface created at top
 94          if UVMConfigDb.get(None, "*", "vif_slave", arr) is True:
 95              UVMConfigDb.set(self, "*", "vif_slave", arr[0])
 96              # Make this agent's interface the interface connected at top
 97              self.wb4s_agent_cfg.vif         = arr[0]
 98              self.wb4s_agent_cfg.has_driver  = 1
 99              self.wb4s_agent_cfg.has_monitor = 1
100          else:
101              uvm_fatal("NOVIF", "Could not get vif_slave from config DB")
102  
103          # Make this instruction agent the test bench config agent
104          self.tb_env_config.wb4s_agent_cfg = self.wb4s_agent_cfg
105  
106          # Place the tn_env_config in the Db. The tb_env will fetch this in its build phase .
107          UVMConfigDb.set(self, "*", "tb_env_config", self.tb_env_config)
108  
109          # Create the test bench environment
110          self.tb_env = tb_env.type_id.create("tb_env", self)
111  
112          # Create a specific depth printer for printing the created topology
113          self.printer = UVMTablePrinter()
114          self.printer.knobs.depth = 3
115  
116  
117      def end_of_elaboration_phase(self, phase):
118          # Print topology
119          uvm_info(self.get_type_name(),
120              sv.sformatf("Printing the test topology :\n%s", self.sprint(self.printer)), UVM_LOW)
121  
122  
123      def extract_phase(self, phase):
124          if(self.tb_env.scoreboard.m_mismatches == 0):
125             self.test_pass = True
126          else:
127             self.test_pass = False
128             self.err_msg += '\nMatches : ' + str(self.tb_env.scoreboard.m_matches)
129             self.err_msg += '\nMismatches : ' + str(self.tb_env.scoreboard.m_mismatches)
130  
131  
132      def report_phase(self, phase):
133          if self.test_pass:
134              uvm_info(self.get_type_name(),
135                  sv.sformatf("\n\n-----------------------------------\n    UVM Test   : %s\n    Matches    : %d\n    Mismatches : %d\n    Pass/Fail  : Pass\n-----------------------------------\n", self.get_type_name(), self.tb_env.scoreboard.m_matches, self.tb_env.scoreboard.m_mismatches), UVM_NONE)
136          else:
137              uvm_fatal(self.get_type_name(), "UVM TEST FAIL\n" +
138                  self.err_msg)
139  
140          cov_print = 0 # 
141          # Coverage Report
142          if (cov_print == 1):
143              # Print coverage bins at the end of the sim
144              coverage.coverage_db.report_coverage(print, bins=False)
145              coverage.coverage_db.report_coverage(print, bins=True)
146  
147          if (self.tb_env_config.has_functional_coverage):
148              coverage.coverage_db.export_to_yaml(filename="coverage_result.yml")
149  
150  
151  uvm_component_utils(test_base)
152  
153  
154  class default_test(test_base):
155      """
156         Class: Default Test
157  
158         Definition: Contains functions, tasks and methods.
159      """
160  
161      def __init__(self, name="default_test", parent=test_base):
162          super().__init__(name, parent)
163          # This class' variables initial state.
164          self.count       = 0
165          self.stall       = 1
166          self.acknowledge = 0
167  
168  
169      async def run_phase(self, phase):
170          phase.raise_objection(self, "default_test raise objection")
171  
172          # Call and fork the methods that create sequences to feed the sequencers
173          slave_proc  = cocotb.fork(self.random_stimulat_intfc())
174          #slave_proc  = cocotb.fork(self.stimulate_slave_intfc())
175  
176          await Timer(16, "NS") # Allow some clocks for evething to settle
177  
178          uvm_info(self.get_type_name(),
179              sv.sformatf("\nSim Started\n"), UVM_LOW)
180          await sv.fork_join_any([slave_proc])
181  
182          uvm_info(self.get_type_name(),
183              sv.sformatf("\nSim Finished\n"), UVM_LOW)
184  
185          phase.drop_objection(self, "default_test drop objection")
186  
187  
188  
189      async def random_stimulat_intfc(self):
190          #
191          top_rng    = int(pow(2, (self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH)/2))
192          #top_rng    = int(pow(2, (self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH)/4))
193          stop_count = 25
194          wb4s_sqr   = self.tb_env.wb4s_agent.sqr
195          
196          # de-assert the CYC and STB signals
197          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
198          increment_sum_seq.data      = 51966 #0xCAFE
199          increment_sum_seq.cycle     = 0
200          increment_sum_seq.strobe    = 0
201          increment_sum_seq.cycle_tag = 1
202  
203          await increment_sum_seq.start(wb4s_sqr)
204          
205          while (stop_count > 0): 
206              stop_count -= 1
207              wb4s_sqr    = self.tb_env.wb4s_agent.sqr
208  
209              # Create transactions to stimulate the slave interface (calc division)
210              increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
211              increment_sum_seq.data      = (rnd.randint(0,top_rng) << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + rnd.randint(0,top_rng)
212              #increment_sum_seq.data      = ((top_rng-1-(stop_count*stop_count*10000)) << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + (top_rng-stop_count-1)
213              increment_sum_seq.strobe    = 1 # rnd.randint(0,2)
214              increment_sum_seq.cycle     = 1 #rnd.randint(0,2)
215              increment_sum_seq.cycle_tag = 1#rnd.randint(0,4)
216  
217              await increment_sum_seq.start(wb4s_sqr)
218  
219          # de-assert the CYC and STB signals
220          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
221          increment_sum_seq.data      = 51966 #0xCAFE
222          increment_sum_seq.cycle     = 0
223          increment_sum_seq.strobe    = 0
224          increment_sum_seq.cycle_tag = 0
225  
226          await increment_sum_seq.start(wb4s_sqr)
227  
228  
229      async def stimulate_slave_intfc(self):
230          #
231          self.count = int(pow(2, (self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH)/2)-1)
232          data_inc   = 3
233          stop_count = self.count + (self.tb_env.cfg.data_bins_range[1] - self.tb_env.cfg.data_bins_range[0])/data_inc
234          wb4s_sqr = self.tb_env.wb4s_agent.sqr
235          
236          # de-assert the CYC and STB signals
237          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
238          increment_sum_seq.data      = 51966 #0xCAFE
239          increment_sum_seq.cycle     = 0
240          increment_sum_seq.strobe    = 0
241          increment_sum_seq.cycle_tag = 0
242  
243          await increment_sum_seq.start(wb4s_sqr)
244  
245          # Create transactions to stimulate the slave interface (calc division)
246          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
247          increment_sum_seq.data      = 0
248          increment_sum_seq.strobe    = 1
249          increment_sum_seq.cycle     = 1
250          increment_sum_seq.cycle_tag = 0
251  
252          await increment_sum_seq.start(wb4s_sqr)
253  
254          # Create transactions to stimulate the slave interface (calc division)
255          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
256          increment_sum_seq.data      = 1
257          increment_sum_seq.strobe    = 1
258          increment_sum_seq.cycle     = 1
259          increment_sum_seq.cycle_tag = 0
260  
261          await increment_sum_seq.start(wb4s_sqr)
262  
263          # Create transactions to stimulate the slave interface (calc division)
264          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
265          increment_sum_seq.data      = 1 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)
266          increment_sum_seq.strobe    = 1
267          increment_sum_seq.cycle     = 1
268          increment_sum_seq.cycle_tag = 0
269  
270          await increment_sum_seq.start(wb4s_sqr)
271          
272          # Create transactions to stimulate the slave interface (calc division)
273          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
274          increment_sum_seq.data      = (1 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 1
275          increment_sum_seq.strobe    = 1
276          increment_sum_seq.cycle     = 1
277          increment_sum_seq.cycle_tag = 0
278  
279          await increment_sum_seq.start(wb4s_sqr)
280          
281          # Create transactions to stimulate the slave interface (calc division)
282          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
283          increment_sum_seq.data      = (0xFFFFFFFF << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 1
284          increment_sum_seq.strobe    = 1
285          increment_sum_seq.cycle     = 1
286          increment_sum_seq.cycle_tag = 3
287  
288          await increment_sum_seq.start(wb4s_sqr)
289  
290          # Create transactions to stimulate the slave interface (calc division)
291          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
292          increment_sum_seq.data      = (0xFFFFFFFF << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 10
293          increment_sum_seq.strobe    = 1
294          increment_sum_seq.cycle     = 1
295          increment_sum_seq.cycle_tag = 3
296  
297          await increment_sum_seq.start(wb4s_sqr)
298  
299          # Create transactions to stimulate the slave interface (calc division)
300          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
301          increment_sum_seq.data      = (3145727 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 4195835
302          increment_sum_seq.strobe    = 1
303          increment_sum_seq.cycle     = 1
304          increment_sum_seq.cycle_tag = 1
305  
306          await increment_sum_seq.start(wb4s_sqr)
307  
308          # Create transactions to stimulate the slave interface (calc division)
309          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
310          increment_sum_seq.data      = (3145727 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 4195835
311          increment_sum_seq.strobe    = 1
312          increment_sum_seq.cycle     = 1
313          increment_sum_seq.cycle_tag = 3
314  
315          await increment_sum_seq.start(wb4s_sqr)
316  
317          # Create transactions to stimulate the slave interface (calc division)
318          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
319          increment_sum_seq.data      = (-3145727 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 4195835
320          increment_sum_seq.strobe    = 1
321          increment_sum_seq.cycle     = 1
322          increment_sum_seq.cycle_tag = 1
323  
324          await increment_sum_seq.start(wb4s_sqr)
325  
326          # Create transactions to stimulate the slave interface (calc division)
327          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
328          increment_sum_seq.data      = (-3145727 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 4195835
329          increment_sum_seq.strobe    = 1
330          increment_sum_seq.cycle     = 1
331          increment_sum_seq.cycle_tag = 3
332  
333          await increment_sum_seq.start(wb4s_sqr)
334  
335          # Create transactions to stimulate the slave interface (calc division)
336          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
337          increment_sum_seq.data      = (112 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 5058
338          increment_sum_seq.strobe    = 1
339          increment_sum_seq.cycle     = 1
340          increment_sum_seq.cycle_tag = 1
341  
342          await increment_sum_seq.start(wb4s_sqr)
343  
344          # Create transactions to stimulate the slave interface (calc division)
345          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
346          increment_sum_seq.data      = (112 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 5058
347          increment_sum_seq.strobe    = 1
348          increment_sum_seq.cycle     = 1
349          increment_sum_seq.cycle_tag = 3
350  
351          await increment_sum_seq.start(wb4s_sqr)
352  
353          # Create transactions to stimulate the slave interface (calc division)
354          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
355          increment_sum_seq.data      = (96 << math.floor(self.tb_env.cfg.DUT_SLAVE_DATA_IN_LENGTH/2)) + 1024
356          increment_sum_seq.strobe    = 1
357          increment_sum_seq.cycle     = 1
358          increment_sum_seq.cycle_tag = 3
359  
360          await increment_sum_seq.start(wb4s_sqr)
361  
362          # de-assert the CYC and STB signals
363          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
364          increment_sum_seq.data      = 0
365          increment_sum_seq.cycle     = 1
366          increment_sum_seq.strobe    = 0
367          increment_sum_seq.cycle_tag = 0
368  
369          await increment_sum_seq.start(wb4s_sqr)
370  
371          # de-assert the CYC and STB signals
372          increment_sum_seq           = wb4s_single_write_seq("increment_sum_seq")
373          increment_sum_seq.data      = 51966 #0xCAFE
374          increment_sum_seq.cycle     = 0
375          increment_sum_seq.strobe    = 0
376          increment_sum_seq.cycle_tag = 0
377  
378          await increment_sum_seq.start(wb4s_sqr)
379  
380  
381  uvm_component_utils(default_test)