Skip to content

Commit

Permalink
Add tests and sequences
Browse files Browse the repository at this point in the history
  • Loading branch information
M0stafaRady committed Apr 30, 2024
1 parent f779587 commit 2ea75e6
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 13 deletions.
2 changes: 1 addition & 1 deletion verify/uvm-python/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ YAML_FILE = $(PWD)/../../EF_SPI.yaml # TODO: update yaml file path
MAKEFLAGS += --no-print-directory

# List of tests
TESTS := spi_first_test
TESTS := MOSI_stress_test MISO_stress_test MISO_MOSI_test spi_csb_test spi_pr_test

# Variable for tag - set this as required
SIM_TAG ?= default_tag
Expand Down
7 changes: 2 additions & 5 deletions verify/uvm-python/spi_agent/spi_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def update_config_regs(self):
self.cpha_val = (config_reg & 0b10) >> 1

async def driving_edge(self):
if self.cpol_val != self.cpha_val:
if self.cpol_val == self.cpha_val:
await RisingEdge(self.vif.SCK)
else:
await FallingEdge(self.vif.SCK)
Expand All @@ -42,11 +42,8 @@ async def run_phase(self, phase):
uvm_info(self.tag, f"Got transaction {tr[0]}", UVM_LOW)
tr = tr[0]
for i in range(7, -1, -1): # drive the most significant bit first
if self.cpha_val == 1:
await self.driving_edge()
self.vif.MISO.value = (tr.MISO >> i) & 0b1
if self.cpha_val == 0:
await self.driving_edge()
await self.driving_edge()
# use self.vif.<signal name> for driving interface signals
self.seq_item_port.item_done()

Expand Down
26 changes: 25 additions & 1 deletion verify/uvm-python/spi_ref_model/spi_ref_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from uvm.macros import uvm_component_utils
from uvm.tlm1.uvm_analysis_port import UVMAnalysisImp
from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW, UVM_MEDIUM
from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info
from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info, uvm_error
from uvm.base.uvm_config_db import UVMConfigDb
from uvm.tlm1.uvm_analysis_port import UVMAnalysisExport
import cocotb
Expand Down Expand Up @@ -30,6 +30,8 @@ def __init__(self, name="spi_ref_model", parent=None):
self.mis_changed = Event()
self.icr_changed = Event()
self.data_to_write = 0 # data for spi to write into the MOSI
self.num_wr_start = 0 # number of writing to the start bit each write when the cs is asserted and spi is not busy a transaction should be sent
self.num_tr = 0 # number of transaction sent this should be always equal or less than num_wr_start by 1

def build_phase(self, phase):
super().build_phase(phase)
Expand Down Expand Up @@ -70,6 +72,11 @@ def write_bus(self, tr):
# check if the write register is icr , set the icr changed event
if tr.addr == self.regs.reg_name_to_address["icr"] and tr.data != 0:
self.icr_changed.set()
# detect writing to start bit
if tr.addr == self.regs.reg_name_to_address["CTRL"]:
if tr.data & 0b11 == 0b11:
self.num_wr_start += 1
self.check_num_tr()
elif tr.kind == bus_item.READ:
# TODO: write logic needed when read transaction is received
# For example, to read the same resgiter uncomment the following lines
Expand All @@ -90,6 +97,12 @@ def write_ip(self, tr):
"Ref model recieved from ip monitor: " + tr.convert2string(),
UVM_HIGH,
)
# check data sent while the csb isn't asserted
if (
self.regs.read_reg_value(self.regs.reg_name_to_address["CTRL"]) & 0b10
== 0b0
):
uvm_error(self.tag, "Data sent while csb is not asserted")
self.regs.write_reg_value(self.regs.reg_name_to_address["DATA"], tr.MISO)
# Update interrupts when a new ip transaction is received
self.set_ris_reg()
Expand All @@ -98,6 +111,8 @@ def write_ip(self, tr):
td = tr.do_clone()
td.MOSI = self.data_to_write
self.ip_export.write(td) # this is output ro scoreboard
self.num_tr += 1
self.check_num_tr()

def set_ris_reg(self):
# TODO: update this function to update the value of 'self.ris_reg' according to the ip transaction
Expand Down Expand Up @@ -152,5 +167,14 @@ async def send_irq_tr(self):

self.mis_changed.clear()

def check_num_tr(self):
if self.num_tr in [self.num_wr_start, self.num_wr_start - 1]:
return True
uvm_error(
self.tag,
f"Number of transaction is not correct expected send tr = {self.num_wr_start} actual send tr = {self.num_tr}",
)
return False


uvm_component_utils(spi_ref_model)
6 changes: 5 additions & 1 deletion verify/uvm-python/spi_seq_lib/configure_spi_seq.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ async def body(self):
# 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="CFG")
await self.send_req(
is_write=True,
reg="CFG",
data_condition=lambda data: data in [0b00, 0b01, 0b10, 0b11],
)


uvm_object_utils(configure_spi_seq)
69 changes: 69 additions & 0 deletions verify/uvm-python/spi_seq_lib/spi_MOSI_MISO_seq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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
import random


class spi_MOSI_MISO_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_MOSI_MISO_seq", num_data=10, data_width=8, disbale_control=False
):
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]
self.disable_control = disbale_control

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
if not self.disable_control:
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b10
)
for _ in range(self.num_data):
if random.random() > 0.3: # 70% probability of writing different value
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
if random.random() > 0.3: # 70% probability of reading
await self.send_req(is_write=False, reg="DATA")
if not self.disable_control:
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b00
) # csb disable


uvm_object_utils(spi_MOSI_MISO_seq)
51 changes: 51 additions & 0 deletions verify/uvm-python/spi_seq_lib/spi_csb_seq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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
import random
from spi_seq_lib.spi_MOSI_MISO_seq import spi_MOSI_MISO_seq


class spi_csb_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_csb_seq", data_width=8):
super().__init__(name)
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
for _ in range(30):
if random.random() > 0.3: # 70% probability of assert csb
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b10
)
await uvm_do(
self,
spi_MOSI_MISO_seq(
name="spi_MOSI_MISO_seq",
num_data=random.randint(1, 10),
disbale_control=True,
),
)
if random.random() > 0.3: # 70% probability of deassert csb
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b00
) # csb disable


uvm_object_utils(spi_csb_seq)
1 change: 0 additions & 1 deletion verify/uvm-python/spi_seq_lib/spi_ip_seq.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ async def body(self):
uvm_info(self.tag, "Add sequence to be used by the ip sequencer", UVM_LOW)
while True:
await uvm_do(self, self.req)
pass


uvm_object_utils(spi_ip_seq)
54 changes: 54 additions & 0 deletions verify/uvm-python/spi_seq_lib/spi_pr_seq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
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
import random
from spi_seq_lib.spi_MOSI_MISO_seq import spi_MOSI_MISO_seq


class spi_pr_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_pr_seq", data_width=8):
super().__init__(name)
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
for _ in range(5):
await self.send_req(
is_write=True,
reg="PR",
data_condition=lambda data: data in range(2, 10),
) # change PR
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b10
)
await uvm_do(
self,
spi_MOSI_MISO_seq(
name="spi_MOSI_MISO_seq",
num_data=random.randint(1, 10),
disbale_control=True,
),
)
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b00
) # csb disable


uvm_object_utils(spi_pr_seq)
63 changes: 63 additions & 0 deletions verify/uvm-python/spi_seq_lib/spi_send_MISO_seq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
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
import random


class spi_send_MISO_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_MISO_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
)
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b11
) # go
for _ in range(self.num_data):

# wait until not busy
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
if random.random() > 0.1: # 90% probability of reading
await self.send_req(is_write=False, reg="DATA")
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b11
) # go
await self.send_req(
is_write=True, reg="CTRL", data_condition=lambda data: data == 0b00
) # csb disable


uvm_object_utils(spi_send_MISO_seq)
Loading

0 comments on commit 2ea75e6

Please sign in to comment.