From 9174134fd98fcca503a70e91dc1ce7a5f215e4d4 Mon Sep 17 00:00:00 2001 From: M0stafaRady Date: Wed, 2 Oct 2024 15:27:34 +0300 Subject: [PATCH] Add new i2c test --- .../uvm-python/i2c_ref_model/i2c_ref_model.py | 6 +- .../i2c_seq_lib/i2c_bus_seq_base.py | 61 ++++++++++++++++++- .../i2c_seq_lib/i2c_write_mul_seq.py | 38 ++++++++++++ .../{i2c_bus_seq.py => i2c_write_read_seq.py} | 37 +---------- verify/uvm-python/test_lib.py | 26 +++++--- 5 files changed, 122 insertions(+), 46 deletions(-) create mode 100644 verify/uvm-python/i2c_seq_lib/i2c_write_mul_seq.py rename verify/uvm-python/i2c_seq_lib/{i2c_bus_seq.py => i2c_write_read_seq.py} (61%) diff --git a/verify/uvm-python/i2c_ref_model/i2c_ref_model.py b/verify/uvm-python/i2c_ref_model/i2c_ref_model.py index 60ba1c1..3a9a132 100644 --- a/verify/uvm-python/i2c_ref_model/i2c_ref_model.py +++ b/verify/uvm-python/i2c_ref_model/i2c_ref_model.py @@ -68,7 +68,7 @@ def write_bus(self, tr): elif td.kind == bus_item.READ: if td.addr == self.regs.reg_name_to_address["Data"]: - td.data = self.fifo_rx.get_nowait() | (0b1 << 8) # add valid data bit + td.data = (self.fifo_rx.get_nowait() | (0b1 << 8)) & 0x1FF # add valid data bit, remove last bit self.bus_bus_export.write(td) # this is output to the scoreboard def decode_command(self, command): @@ -198,9 +198,9 @@ def write(self, address, value): if not (0 <= address < self.size): raise ValueError(f"Invalid address {address}. Must be between 0 and {self.size - 1}.") if not (0 <= value <= self.max_value): - raise ValueError(f"Invalid value {value}. Must be between 0 and {self.max_value}.") + uvm_warning("MemoryBlock",f"Invalid value {value}. Must be between 0 and {self.max_value}.") self.memory[address] = value - uvm_info("MemoryBlock",f"Wrote value {hex(value)} to address {hex(address)}.", UVM_LOW) + uvm_info("MemoryBlock",f"Wrote value {hex(value)} to address {hex(address)}.", UVM_HIGH) diff --git a/verify/uvm-python/i2c_seq_lib/i2c_bus_seq_base.py b/verify/uvm-python/i2c_seq_lib/i2c_bus_seq_base.py index 777b845..82dca50 100644 --- a/verify/uvm-python/i2c_seq_lib/i2c_bus_seq_base.py +++ b/verify/uvm-python/i2c_seq_lib/i2c_bus_seq_base.py @@ -20,6 +20,9 @@ def __init__(self, name="i2c_bus_seq_base"): uvm_fatal(self.tag, "No json file wrapper regs") else: self.regs = regs_arr[0] + self.slave0 = slave_valid_addr(0b1010101) + self.slave1 = slave_valid_addr(0b1010110) + async def body(self): await super().body() @@ -28,7 +31,30 @@ async def body(self): async def change_PR(self, val): await self.send_req(is_write=True, reg="PR", data_value=val) - + + async def write_multiple(self, slave_address, address, data): + uvm_info(self.tag, f"write_multiple slave address = 0x{slave_address:X}, address = 0x{address:X}, data = {data}", UVM_MEDIUM) + # address write_mul + commad_write = slave_address | 1 << 10 + command_write_mul = slave_address | 1 << 11 + await self.wait_data_fifo_not_full() + await self.send_req(is_write=True, reg="Command", data_value=commad_write) # issue write command + await self.send_req(is_write=True, reg="Data", data_value=(address>>8) & 0xFF) # address high + await self.wait_data_fifo_not_full() + await self.send_req(is_write=True, reg="Command", data_value=commad_write) # issue write command + await self.send_req(is_write=True, reg="Data", data_value=address & 0xFF) # address low + # write mul + await self.send_req(is_write=True, reg="Command", data_value=command_write_mul) # issue write command + for i in data[:-1]: # data + await self.wait_data_fifo_not_full() + await self.send_req(is_write=True, reg="Data", data_value=i) # data + # send last data and add data last bit + await self.wait_data_fifo_not_full() + await self.send_req(is_write=True, reg="Data", data_value=data[-1] | 1 << 9) # data + command_stop = slave_address | 1 << 12 # stop + await self.send_req(is_write=True, reg="Command", data_value=command_stop) # issue write command + await Timer(100, "us") + async def write_address(self, slave_address, address, data): uvm_info(self.tag, f"write_address slave address = 0x{slave_address:X}, address = 0x{address:X}, data = {data}", UVM_MEDIUM) # address write @@ -49,7 +75,7 @@ async def write_address(self, slave_address, address, data): async def read_address(self, slave_address, address, number_of_reads=1): # address read - commad_write = slave_address | 1 << 10 + commad_write = slave_address | 1 << 10 commad_read = slave_address | 1 << 9 await self.wait_data_fifo_not_full() await self.send_req(is_write=True, reg="Command", data_value=commad_write) # issue read command @@ -101,3 +127,34 @@ async def wait_data_rx_not_empty(self): await self.send_nop() uvm_object_utils(i2c_bus_seq_base) + + + +class slave_valid_addr(): + def __init__(self, address): + self.slave_address = address + self.valid_address = [] + + def write_address(self): + address = random.randint(0, 8191) & 0x1FE0 # 0x1FE0 ensures the first 5 bits are 0 + number_of_data = random.randint(1, 7) + for i in range(number_of_data): + self.valid_address.append(address + i) + return (self.slave_address, "write",address, number_of_data) + + def read_address(self): + if len(self.valid_address) == 0: + return self.write_address() + address = random.choice(self.valid_address) + number_of_data = random.randint(1, 7) + for i in range(number_of_data): + if (address + i) not in self.valid_address: + number_of_data = i + break + return (self.slave_address, "read", address, number_of_data) + + def choose_op(self): + if random.random() > 0.75: + return self.write_address() + else: + return self.read_address() \ No newline at end of file diff --git a/verify/uvm-python/i2c_seq_lib/i2c_write_mul_seq.py b/verify/uvm-python/i2c_seq_lib/i2c_write_mul_seq.py new file mode 100644 index 0000000..cebf723 --- /dev/null +++ b/verify/uvm-python/i2c_seq_lib/i2c_write_mul_seq.py @@ -0,0 +1,38 @@ +from uvm.seq import UVMSequence +from uvm.macros.uvm_object_defines import uvm_object_utils +from uvm.macros.uvm_message_defines import uvm_fatal +from uvm.base.uvm_config_db import UVMConfigDb +from EF_UVM.bus_env.bus_seq_lib.bus_seq_base import bus_seq_base +from cocotb.triggers import Timer +from uvm.macros.uvm_sequence_defines import uvm_do_with, uvm_do +from i2c_seq_lib.i2c_bus_seq_base import i2c_bus_seq_base +import random +from uvm.macros import uvm_component_utils, uvm_info, uvm_error, uvm_warning +from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW, UVM_MEDIUM + + +class i2c_write_mul_seq(i2c_bus_seq_base): + # use this sequence write or read from register by the bus interface + # this sequence should be connected to the bus sequencer in the testbench + # you should create as many sequences as you need not only this one + def __init__(self, name="i2c_write_mul_seq"): + super().__init__(name) + + async def body(self): + await super().body() + address = random.randint(0, 8191) + data = [random.randint(0, 255) for i in range(random.randint(1, 10))] + for i in range(10): + if random.random() > 0.5: + slave_address = self.slave0.slave_address + else: + slave_address = self.slave1.slave_address + await self.write_multiple(slave_address, address, data) + await self.read_address(slave_address, address, len(data)) + # read rx fifo + for i in range(len(data)): + await self.wait_data_rx_not_empty() + await self.send_req(is_write=False, reg="Data") # read all so the fifo will not get full + + +uvm_object_utils(i2c_write_mul_seq) \ No newline at end of file diff --git a/verify/uvm-python/i2c_seq_lib/i2c_bus_seq.py b/verify/uvm-python/i2c_seq_lib/i2c_write_read_seq.py similarity index 61% rename from verify/uvm-python/i2c_seq_lib/i2c_bus_seq.py rename to verify/uvm-python/i2c_seq_lib/i2c_write_read_seq.py index 211e75f..d616c8f 100644 --- a/verify/uvm-python/i2c_seq_lib/i2c_bus_seq.py +++ b/verify/uvm-python/i2c_seq_lib/i2c_write_read_seq.py @@ -11,14 +11,13 @@ from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW, UVM_MEDIUM -class i2c_bus_seq(i2c_bus_seq_base): +class i2c_write_read_seq(i2c_bus_seq_base): # use this sequence write or read from register by the bus interface # this sequence should be connected to the bus sequencer in the testbench # you should create as many sequences as you need not only this one def __init__(self, name="i2c_bus_seq"): super().__init__(name) - self.slave0 = slave_valid_addr(0b1010101) - self.slave1 = slave_valid_addr(0b1010110) + async def body(self): await super().body() for i in range(100): @@ -38,34 +37,4 @@ async def body(self): await self.wait_data_rx_not_empty() await self.send_req(is_write=False, reg="Data") # read all so the fifo will not get full -uvm_object_utils(i2c_bus_seq) - - -class slave_valid_addr(): - def __init__(self, address): - self.slave_address = address - self.valid_address = [] - - def write_address(self): - address = random.randint(0, 8191) & 0x1FE0 # 0x1FE0 ensures the first 5 bits are 0 - number_of_data = random.randint(1, 7) - for i in range(number_of_data): - self.valid_address.append(address + i) - return (self.slave_address, "write",address, number_of_data) - - def read_address(self): - if len(self.valid_address) == 0: - return self.write_address() - address = random.choice(self.valid_address) - number_of_data = random.randint(1, 7) - for i in range(number_of_data): - if (address + i) not in self.valid_address: - number_of_data = i - break - return (self.slave_address, "read", address, number_of_data) - - def choose_op(self): - if random.random() > 0.75: - return self.write_address() - else: - return self.read_address() \ No newline at end of file +uvm_object_utils(i2c_bus_seq_base) \ No newline at end of file diff --git a/verify/uvm-python/test_lib.py b/verify/uvm-python/test_lib.py index fbeb5a0..300c990 100644 --- a/verify/uvm-python/test_lib.py +++ b/verify/uvm-python/test_lib.py @@ -12,7 +12,8 @@ from EF_UVM.base_test import base_test # seqences import -from i2c_seq_lib.i2c_bus_seq import i2c_bus_seq +from i2c_seq_lib.i2c_write_read_seq import i2c_write_read_seq +from i2c_seq_lib.i2c_write_mul_seq import i2c_write_mul_seq from i2c_seq_lib.i2c_ip_seq import i2c_ip_seq # override classes @@ -82,7 +83,7 @@ def build_phase(self, phase): uvm_component_utils(i2c_base_test) -class i2c_first_test(i2c_base_test): +class i2c_write_read_test(i2c_base_test): def __init__(self, name="i2c__first_test", parent=None): super().__init__(name, parent=parent) self.tag = name @@ -90,12 +91,23 @@ def __init__(self, name="i2c__first_test", parent=None): async def main_phase(self, phase): uvm_info(self.tag, f"Starting test {self.__class__.__name__}", UVM_LOW) phase.raise_objection(self, f"{self.__class__.__name__} OBJECTED") - bus_seq = i2c_bus_seq("i2c_bus_seq") - ip_seq = i2c_ip_seq("i2c_ip_seq") + bus_seq = i2c_write_read_seq("i2c_write_read_seq") await bus_seq.start(self.bus_sqr) - # await ip_seq.start(self.ip_sqr) - await Timer(100000 , "ns") + await Timer(10000 , "ns") + phase.drop_objection(self, f"{self.__class__.__name__} drop objection") + +class i2c_write_mul_test(i2c_base_test): + def __init__(self, name="i2c_write_mul_test", parent=None): + super().__init__(name, parent=parent) + self.tag = name + + async def main_phase(self, phase): + uvm_info(self.tag, f"Starting test {self.__class__.__name__}", UVM_LOW) + phase.raise_objection(self, f"{self.__class__.__name__} OBJECTED") + bus_seq = i2c_write_mul_seq("i2c_write_mul_seq") + await bus_seq.start(self.bus_sqr) + await Timer(10000 , "ns") phase.drop_objection(self, f"{self.__class__.__name__} drop objection") -uvm_component_utils(i2c_first_test) +uvm_component_utils(i2c_write_mul_test)