From f779587f29d761f6d3eb5cd8ce23ef9d092d105e Mon Sep 17 00:00:00 2001 From: M0stafaRady Date: Mon, 29 Apr 2024 16:34:46 +0300 Subject: [PATCH] Add coverage and update the ref model --- EF_SPI.yaml | 2 +- hdl/rtl/bus_wrappers/APB_SPI.v | 14 ++++- .../uvm-python/spi_coverage/ip_cov_groups.py | 58 ++++++++++++++++++ .../uvm-python/spi_coverage/spi_coverage.py | 11 +++- .../uvm-python/spi_ref_model/spi_ref_model.py | 5 +- verify/uvm-python/spi_seq_lib/spi_bus_seq.py | 14 +++-- .../spi_seq_lib/spi_send_MOSI_seq.py | 61 +++++++++++++++++++ verify/uvm-python/test_lib.py | 3 +- 8 files changed, 154 insertions(+), 14 deletions(-) create mode 100644 verify/uvm-python/spi_coverage/ip_cov_groups.py create mode 100644 verify/uvm-python/spi_seq_lib/spi_send_MOSI_seq.py diff --git a/EF_SPI.yaml b/EF_SPI.yaml index e2a93c1..1aa72db 100644 --- a/EF_SPI.yaml +++ b/EF_SPI.yaml @@ -186,7 +186,7 @@ registers: bit_offset: 0 bit_width: 1 write_port: "" - description: "" + description: "self clear field" - name: SSn bit_offset: 1 bit_width: 1 diff --git a/hdl/rtl/bus_wrappers/APB_SPI.v b/hdl/rtl/bus_wrappers/APB_SPI.v index 2b7be65..4cd965d 100644 --- a/hdl/rtl/bus_wrappers/APB_SPI.v +++ b/hdl/rtl/bus_wrappers/APB_SPI.v @@ -82,10 +82,20 @@ module EF_SPI_APB( `APB_SPI_REG(DATA_REG, 8, 0, DATA_REG_sel, DATA_REG_OFF) `APB_SPI_REG(CFG_REG, 2, 0, CFG_REG_sel, CFG_REG_OFF) - `APB_SPI_REG(CTRL_REG, 2, 0, CTRL_REG_sel, CTRL_REG_OFF) + // `APB_SPI_REG(CTRL_REG, 2, 0, CTRL_REG_sel, CTRL_REG_OFF) `APB_SPI_REG(PRE_REG, 8, 2, PRE_REG_sel, PRE_REG_OFF) `APB_SPI_REG(IM_REG, 1, 0, IM_REG_sel, IM_REG_OFF) - + // make CTRL_REG[0] self clear register + reg [1:0] CTRL_REG; + wire CTRL_REG_sel = PENABLE & PWRITE & PREADY & PSEL & (PADDR[7:3] == CTRL_REG_OFF); + always @(posedge PCLK or negedge PRESETn) + if (~PRESETn) + CTRL_REG <= 0; + else if (CTRL_REG_sel) + CTRL_REG <= PWDATA[1:0]; + else + CTRL_REG[0] <= 1'b0; + reg IC_REG; wire IC_REG_sel = (PENABLE & PWRITE & PREADY & PSEL & (PADDR[7:3] == IC_REG_OFF)); always @(posedge PCLK, negedge PRESETn) diff --git a/verify/uvm-python/spi_coverage/ip_cov_groups.py b/verify/uvm-python/spi_coverage/ip_cov_groups.py new file mode 100644 index 0000000..934222d --- /dev/null +++ b/verify/uvm-python/spi_coverage/ip_cov_groups.py @@ -0,0 +1,58 @@ +from uvm.macros.uvm_message_defines import uvm_info +from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW +from cocotb_coverage.coverage import CoverPoint, CoverCross +from uvm.macros import uvm_component_utils + + +class ip_cov_groups: + def __init__(self, hierarchy, regs) -> None: + self.hierarchy = hierarchy + self.regs = regs + self.ip_cov(None, do_sampling=False) + self.item_width = 8 + + def ip_cov(self, tr, do_sampling=True): + @CoverPoint( + f"{self.hierarchy}.MISO", + xf=lambda tr: tr.MISO, + bins=[(0, 0xF), (0x10, 0xF0), (0xF1, 0xFF)], + at_least=3, + rel=lambda val, b: b[0] <= val <= b[1], + ) + @CoverPoint( + f"{self.hierarchy}.MOSI", + xf=lambda tr: tr.MOSI, + bins=[(0, 0xF), (0x10, 0xF0), (0xF1, 0xFF)], + at_least=3, + rel=lambda val, b: b[0] <= val <= b[1], + ) + @CoverPoint( + f"{self.hierarchy}.clock_polarity", + xf=lambda tr: self.regs.read_reg_value("CFG") & 0b1, + bins=[False, True], + bins_labels=["normal", "inverted"], + at_least=3, + ) + @CoverPoint( + f"{self.hierarchy}.clock_phase", + xf=lambda tr: (self.regs.read_reg_value("CFG") & 0b10) >> 1, + bins=[False, True], + bins_labels=["normal", "shifted90"], + at_least=3, + ) + @CoverPoint( + f"{self.hierarchy}.PRESCALER", + xf=lambda tr: self.regs.read_reg_value("PR"), + bins=[(0, 0x5), (0x5, 0xFFFF)], + at_least=3, + rel=lambda val, b: b[0] <= val <= b[1], + ) + @CoverCross( + f"{self.hierarchy}.clock_polarity_phase", + items=[f"{self.hierarchy}.clock_polarity", f"{self.hierarchy}.clock_phase"], + ) + def sample(tr): + uvm_info("coverage_ip", f"tr = {tr}", UVM_LOW) + + if do_sampling: + sample(tr) diff --git a/verify/uvm-python/spi_coverage/spi_coverage.py b/verify/uvm-python/spi_coverage/spi_coverage.py index fbfa8de..87cd62b 100644 --- a/verify/uvm-python/spi_coverage/spi_coverage.py +++ b/verify/uvm-python/spi_coverage/spi_coverage.py @@ -6,6 +6,7 @@ from uvm.base.uvm_config_db import UVMConfigDb from uvm.macros.uvm_tlm_defines import uvm_analysis_imp_decl from EF_UVM.ip_env.ip_coverage.ip_coverage import ip_coverage +from spi_coverage.ip_cov_groups import ip_cov_groups class spi_coverage(ip_coverage): @@ -19,11 +20,15 @@ def __init__(self, name="spi_coverage", parent=None): def build_phase(self, phase): super().build_phase(phase) # TODO: initialize the class for coverage groups here + arr = [] + if not UVMConfigDb.get(self, "", "bus_regs", arr): + uvm_fatal(self.tag, "No json file wrapper regs") + else: + regs = arr[0] + self.cov_groups = ip_cov_groups("top.ip", regs) def write(self, tr): - # called when new transaction from ip monitor is received - # TODO: Add sampling logic here - pass + self.cov_groups.ip_cov(tr) uvm_component_utils(spi_coverage) diff --git a/verify/uvm-python/spi_ref_model/spi_ref_model.py b/verify/uvm-python/spi_ref_model/spi_ref_model.py index a33d41d..a6473d2 100644 --- a/verify/uvm-python/spi_ref_model/spi_ref_model.py +++ b/verify/uvm-python/spi_ref_model/spi_ref_model.py @@ -75,7 +75,10 @@ def write_bus(self, tr): # For example, to read the same resgiter uncomment the following lines data = self.regs.read_reg_value(tr.addr) td = tr.do_clone() - td.data = data + if tr.addr == self.regs.reg_name_to_address["STATUS"]: + pass # don't change the data as the status register isnt calculated in the ref model for now + else: + td.data = data self.bus_bus_export.write(td) # this is output to the scoreboard self.update_interrupt_regs() diff --git a/verify/uvm-python/spi_seq_lib/spi_bus_seq.py b/verify/uvm-python/spi_seq_lib/spi_bus_seq.py index fd21adc..3f17dca 100644 --- a/verify/uvm-python/spi_seq_lib/spi_bus_seq.py +++ b/verify/uvm-python/spi_seq_lib/spi_bus_seq.py @@ -29,18 +29,20 @@ async def body(self): await self.send_req( is_write=True, reg="CTRL", data_condition=lambda data: data == 0b11 ) - + for _ in range(50): + await self.send_nop() await self.send_req( is_write=True, reg="CTRL", data_condition=lambda data: data == 0b11 ) - for _ in range(50): - await self.send_nop() - await self.send_req( is_write=True, reg="PR", data_condition=lambda data: data > 2 and data < 10 ) - - for _ in range(500): + for _ in range(300): + await self.send_nop() + await self.send_req( + is_write=True, reg="CTRL", data_condition=lambda data: data == 0b11 + ) + for _ in range(200): await self.send_nop() diff --git a/verify/uvm-python/spi_seq_lib/spi_send_MOSI_seq.py b/verify/uvm-python/spi_seq_lib/spi_send_MOSI_seq.py new file mode 100644 index 0000000..047a498 --- /dev/null +++ b/verify/uvm-python/spi_seq_lib/spi_send_MOSI_seq.py @@ -0,0 +1,61 @@ +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 uvm.base.uvm_object_globals import UVM_ALL_ON, UVM_NOPACK, UVM_HIGH, UVM_MEDIUM +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info + + +class spi_send_MOSI_seq(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="spi_send_MOSI_seq", num_data=10, data_width=8): + super().__init__(name) + self.num_data = num_data + self.data_width = data_width + regs_arr = [] + if not UVMConfigDb.get(self, "", "bus_regs", regs_arr): + uvm_fatal(self.tag, "No json file wrapper regs") + else: + self.regs = regs_arr[0] + + async def body(self): + await super().body() + # Add the sequqnce here + # you could use method send_req to send a write or read using the register name + # example for writing register by value > 5 + await self.send_req( + is_write=True, reg="CTRL", data_condition=lambda data: data == 0b10 + ) + for _ in range(self.num_data): + await self.send_req( + is_write=True, + reg="DATA", + data_condition=lambda data: data < (1 << self.data_width) - 1, + ) + await self.send_req( + is_write=True, reg="CTRL", data_condition=lambda data: data == 0b11 + ) # go + while True: + await self.send_req(is_write=False, reg="STATUS") + # pop non needed response in the fifo + while True: + rsp = [] + await self.get_response(rsp) + rsp = rsp[0] + uvm_info(self.get_full_name(), f"RSP: {rsp}", UVM_MEDIUM) + if rsp.addr == self.regs.reg_name_to_address["STATUS"]: + break + if rsp.data & 0b10 == 0b0: # not busy + break + + await self.send_req( + is_write=True, reg="CTRL", data_condition=lambda data: data == 0b00 + ) # csb disable + + +uvm_object_utils(spi_send_MOSI_seq) diff --git a/verify/uvm-python/test_lib.py b/verify/uvm-python/test_lib.py index 46e89ac..853635b 100644 --- a/verify/uvm-python/test_lib.py +++ b/verify/uvm-python/test_lib.py @@ -19,6 +19,7 @@ # seqences import from spi_seq_lib.spi_bus_seq import spi_bus_seq from spi_seq_lib.spi_ip_seq import spi_ip_seq +from spi_seq_lib.spi_send_MOSI_seq import spi_send_MOSI_seq from spi_seq_lib.configure_spi_seq import configure_spi_seq # override classes @@ -109,7 +110,7 @@ async def main_phase(self, phase): phase.raise_objection(self, f"{self.__class__.__name__} OBJECTED") # TODO: conntect sequence with sequencer here # for example if you need to run the 2 sequence sequentially - bus_seq = spi_bus_seq("spi_bus_seq") + bus_seq = spi_send_MOSI_seq("spi_send_MOSI_seq") ip_seq = spi_ip_seq("spi_ip_seq") await cocotb.start(ip_seq.start(self.ip_sqr)) await bus_seq.start(self.bus_sqr)