Skip to content

Commit

Permalink
Add an agent to drive register interface of TinyALU_reg
Browse files Browse the repository at this point in the history
- Add dummy reb block and a uvm_agent to drive
  register interface from testbench
- Fix errors with method signatures
- Fix errors with creation of default map
- Update bus2reg to return uvm_reg_op

Signed-off-by: Raviteja Chatta <crteja@lowrisc.org>
  • Loading branch information
crteja authored and raysalemi committed Aug 21, 2023
1 parent f73183a commit c1dacab
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 7 deletions.
131 changes: 131 additions & 0 deletions examples/TinyALU_reg/simple_bus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from cocotb.triggers import RisingEdge
from pyuvm import *
from pyuvm import uvm_sequence_item
from pyuvm.s24_uvm_reg_includes import uvm_reg_bus_op


class simple_bus_item(uvm_sequence_item):
def __init__(self, name):
super().__init__(name)
self.rdata = 0
self.read = 0
self.addr = 0
self.wmask = 0
self.wdata = 0


class simple_bus_driver(uvm_driver):
def __init__(self, name, parent):
super().__init__(name, parent)
self.item: simple_bus_item = None
self.vif = None

def build_phase(self):
self.ap = uvm_analysis_port("ap", self)
self.vif = self.cdb_get(self.get_full_name(), "vif")
if self.vif is None:
raise UVMError("dut handle not available in driver")

async def drive(self, item: simple_bus_item):
# Wait for one clock
RisingEdge(self.vif.clk)
# Drive valid
self.vif.valid = 1
# Drive addr
self.vif.addr = item.addr
# Drive read bit
self.vif.read = item.read
# Drive wmask
self.vif.wmask = item.wmask
self.vif.wdata = item.wdata

async def run_phase(self):
while True:
item = await self.seq_item_port.get_next_item()
await self.drive(item)
self.ap.write(item)
self.seq_item_port.item_done()


class simple_bus_monitor(uvm_monitor):
def __init__(self, name, parent):
super().__init__(name, parent)

def build_phase(self):
super().build_phase()
self.ap = uvm_analysis_port("ap", self)
self.vif = self.cdb_get(self.get_full_name(), "vif")
if self.vif is None:
raise UVMError("dut handle not available in driver")

async def run_phase(self):
while True:
# Wait for one clock
RisingEdge(self.vif.clk)
if self.vif.resetn != 0:
if self.vif.valid == 1:
item = simple_bus_item("item")
item.addr = self.vif.addr
item.read = self.read
item.wmask = self.wmask
item.wdata = self.wdata
item.rdata = self.vif.rdata
self.logger.debug(f"MONITORED {item}")
self.ap.write(item)


class simple_bus_agent(uvm_agent):
def __init__(self, name, parent):
super().__init__(name, parent)
self.seqr: uvm_sequencer = None
self.monitor: uvm_monitor = None
self.driver: uvm_driver = None

def build_phase(self):
super().build_phase()
self.seqr = uvm_sequencer("simple_bus_seqr", self)
self.driver = uvm_driver("simple_bus_driver", self)
self.monitor = uvm_monitor("simple_bus_monitor", self)

def connect_phase(self):
super().connect_phase()
self.driver.seq_item_port.connect(self.seqr.seq_item_export)


class simple_bus_adapter(uvm_reg_adapter):
def __init__(self, name="uvm_reg_adapter"):
super().__init__(name)

# uvm_
def reg2bus(rw: uvm_reg_bus_op) -> uvm_sequence_item:
item = simple_bus_item("reg_seq_item")
# Set read bit
if rw == uvm_access_e.UVM_READ:
item.read = 1
else:
item.read = 0
# set addr
item.addr = rw.addr
# set write mask
item.wmask = rw.byte_en
# Set write data
item.wdata = rw.data
return item

# uvm_reg_bus_op is not created but updated and returned
def bus2reg(bus_item: uvm_sequence_item, rw: uvm_reg_bus_op):
if bus_item.read == 1:
rw.kind = uvm_access_e.UVM_READ
else:
rw.kind = uvm_access_e.UVM_WRITE
# Set addr
rw.addr = bus_item.addr
# Set write data
rw.data = bus_item.wdata
# Set nbits
rw.n_bits = bus_item.wmask.bit_count()
# Set byte_en
rw.byte_en = bus_item.wmask
# Set status
rw.status = uvm_status_e.UVM_IS_OK
return rw
22 changes: 19 additions & 3 deletions examples/TinyALU_reg/testbench.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from simple_bus import simple_bus_agent, simple_bus_adapter
from cocotb.clock import Clock
from cocotb.triggers import Join, Combine
from pyuvm import *
Expand Down Expand Up @@ -240,6 +241,11 @@ async def run_phase(self):
self.ap.write(datum)


# Dummy reg map
class alu_reg_block(uvm_reg_block):
pass


class AluEnv(uvm_env):

def build_phase(self):
Expand All @@ -249,12 +255,19 @@ def build_phase(self):
self.cmd_mon = Monitor("cmd_mon", self, "get_cmd")
self.coverage = Coverage("coverage", self)
self.scoreboard = Scoreboard("scoreboard", self)
self.reg_agent = simple_bus_agent("simple_bus_agent", self)
self.reg_adapter = simple_bus_adapter("reg_adapter")
self.reg_block = alu_reg_block("alu_reg_block")
# Create default map
self.reg_block.blk_create_map("map", 0)

def connect_phase(self):
self.driver.seq_item_port.connect(self.seqr.seq_item_export)
self.cmd_mon.ap.connect(self.scoreboard.cmd_export)
self.cmd_mon.ap.connect(self.coverage.analysis_export)
self.driver.ap.connect(self.scoreboard.result_export)
self.reg_block.def_map.set_sequencer(self.reg_agent.seqr)
self.reg_block.def_map.set_adapter(self.reg_adapter)


@pyuvm.test()
Expand All @@ -269,9 +282,12 @@ def end_of_elaboration_phase(self):

async def run_phase(self):
self.raise_objection()
# Start clock
clock = Clock(cocotb.top.clk, 1, units="ns")
cocotb.start_soon(clock.start())
if cocotb.LANGUAGE == "verilog":
# Start clock
clock = Clock(cocotb.top.clk, 1, units="ns")
cocotb.start_soon(clock.start())
# Pass dut to environment
self.cdb_set("env.simple_bus_agent", cocotb.top, "vif")
await self.test_all.start()
self.drop_objection()

Expand Down
5 changes: 3 additions & 2 deletions pyuvm/s18_uvm_reg_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ def blk_add_map(self, map_i: uvm_reg_map):
uvm_fatal(self.gen_message("blk_add_map -- register block should \
be locked"))

if (self.map_mapping[map_i] is True):
if map_i in self.map_mapping.keys() and \
self.map_mapping[map_i] is True:
uvm_fatal(self.header)
else:
self.maps.append(map_i)
Expand All @@ -199,7 +200,7 @@ def blk_add_map(self, map_i: uvm_reg_map):
# blk_create_map byte_addressing and byte_en
# along with endianess not yet supported
def blk_create_map(self, name: str, base_addr: int):
lmap = uvm_reg_map.create(name, self)
lmap = uvm_reg_map.create(name)
lmap.configure(self, base_addr)
self.blk_add_map(lmap)

Expand Down
4 changes: 2 additions & 2 deletions pyuvm/s21_uvm_reg_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ async def process_write_operation(self, reg_address, data_to_be_written,
local_item = uvm_sequence_item()
local_sequence.copy(local_item)
# Assign the response and read data back
local_adapter.bus2reg(local_item, local_bus_op)
local_bus_op = local_adapter.bus2reg(local_item, local_bus_op)
# Invoke the prediction
if (enable_auto_predict is True):
local_predictor = self.get_predictor()
Expand Down Expand Up @@ -281,7 +281,7 @@ async def process_read_operation(self, reg_address, path: path_t,
local_item = uvm_sequence_item
local_sequence.copy(local_item)
# Assign the response and read data back
local_adapter.bus2reg(local_item, local_bus_op)
local_bus_op = local_adapter.bus2reg(local_item, local_bus_op)
# Invoke the prediction
if (enable_auto_predict is True):
local_predictor = self.get_predictor()
Expand Down

0 comments on commit c1dacab

Please sign in to comment.