77import cocotb
88from cocotb .clock import Clock
99from cocotb .triggers import RisingEdge , ClockCycles
10- from drivers import MIMasterDriverTB as MIMasterDriver
11- from drivers import MISlaveDriverTB as MISlaveDriver
12- from cocotbext .ofm .mi .monitors import MIMasterMonitor , MISlaveMonitor
10+ from cocotbext . ofm . mi . drivers import MIRequestDriverAgent , MIResponseDriverAgent
11+ from cocotbext . ofm . mi . proxymonitor import MIProxyMonitor
12+ from cocotbext .ofm .mi .monitors import MIMonitor
1313from cocotbext .ofm .ver .generators import random_packets
14+ from cocotbext .ofm .utils .math import ceildiv
1415from cocotb_bus .drivers import BitDriver
15- from cocotb_bus .scoreboard import Scoreboard
16+ from scoreboard import Scoreboard
17+ from cocotbext .ofm .mi .transaction import MiRequestTransaction , MiResponseTransaction , MiTransaction , MiTransactionType
18+ from cocotb .binary import BinaryValue
19+ from cocotbext .ofm .utils .signals import filter_bytes_by_bitmask
1620
1721import itertools
22+ from random import choice , randint
1823
1924
2025class testbench ():
2126 def __init__ (self , dut , debug = False ):
2227 self .dut = dut
23- self .master_stream_in = MIMasterDriver (dut , "IN" , dut .CLK )
24- self .master_stream_out = MIMasterMonitor (dut , "OUT" , dut .CLK )
25- self .slave_stream_in = MISlaveDriver (dut , "OUT" , dut .CLK )
26- self .slave_stream_out = MISlaveMonitor (dut , "IN" , dut .CLK )
28+ self .request_stream_in = MIRequestDriverAgent (dut , "IN" , dut .CLK )
29+ self .response_stream_out = MIMonitor (dut , "OUT" , dut .CLK )
30+ self .response_proxy = MIProxyMonitor (self .response_stream_out , MiTransactionType .Request )
31+ self .response_stream_in = MIResponseDriverAgent (dut , "OUT" , dut .CLK )
32+ self .request_stream_out = MIMonitor (dut , "IN" , dut .CLK )
33+ self .request_proxy = MIProxyMonitor (self .request_stream_out , MiTransactionType .Response )
2734
2835 self .backpressure = BitDriver (dut .OUT_ARDY , dut .CLK )
2936
30- # Create a scoreboard on the master_stream_out bus
37+ # Create a scoreboard on the response_stream_out bus
3138 self .pkts_sent = 0
32- self .expected_output_master = []
33- self .expected_output_slave = []
39+ self .expected_output = []
3440 self .scoreboard = Scoreboard (dut )
35- self .scoreboard .add_interface (self .master_stream_out , self .expected_output_master )
36- self .scoreboard .add_interface (self .slave_stream_out , self .expected_output_slave )
41+ self .scoreboard .add_interface (self .response_proxy , self .expected_output )
42+ self .scoreboard .add_interface (self .request_proxy , self .expected_output )
3743
3844 if debug :
39- self .master_stream_in .log .setLevel (cocotb .logging .DEBUG )
40- self .master_stream_out .log .setLevel (cocotb .logging .DEBUG )
45+ self .request_stream_in .log .setLevel (cocotb .logging .DEBUG )
46+ self .response_stream_out .log .setLevel (cocotb .logging .DEBUG )
4147
42- def model (self , transaction : bytes , testcase : int ):
48+ def model (self , test_trans : MiTransaction ):
4349 """Model the DUT based on the input transaction"""
44- if testcase == 0 :
45- self .expected_output_slave .append (transaction )
46- else :
47- self .expected_output_master .append (transaction )
4850
51+ self .expected_output .append (test_trans )
4952 self .pkts_sent += 1
5053
5154 async def reset (self ):
@@ -59,58 +62,72 @@ async def reset(self):
5962async def run_test (dut , pkt_count : int = 1000 , item_width_min : int = 1 , item_width_max : int = 32 ):
6063 # Start clock generator
6164 cocotb .start_soon (Clock (dut .CLK , 5 , units = 'ns' ).start ())
62- tb = testbench (dut )
65+ tb = testbench (dut , debug = False )
6366 await tb .reset ()
6467
6568 tb .backpressure .start ((1 , i % 5 ) for i in itertools .count ())
6669
67- for testcase in range ( 2 ):
68- """two test cases - read = 0, write = 1"""
70+ item_count = 0
71+ trans_cntr = 0
6972
70- item_count = 0
73+ for transaction in random_packets (item_width_min , item_width_max , pkt_count ):
74+ trans_cntr += 1
75+ request_type = choice ([MiTransactionType .Request , MiTransactionType .Response ])
76+ start_addr = randint (0 , 2 ** (tb .request_stream_in .addr_width * 8 )- 1 )
7177
72- for transaction in random_packets (item_width_min , item_width_max , pkt_count ):
73- left_to_enable = len (transaction )
78+ addr = start_addr
79+ offset_transaction = transaction
80+ byte_enable = BinaryValue (2 ** len (transaction ) - 1 )
7481
75- cycles = (len (transaction ) + (tb .master_stream_in .data_width - 1 )) // tb .master_stream_in .data_width
82+ start_offset = addr % tb .request_stream_in .data_width
83+ end_offset = - (addr + len (offset_transaction )) % tb .request_stream_in .data_width
7684
77- item_count += cycles
85+ offset_transaction = bytes (start_offset ) + offset_transaction + bytes (end_offset )
86+ byte_enable = BinaryValue (("0" * start_offset ) + byte_enable .binstr + ("0" * end_offset ))
87+ addr = addr - start_offset
7888
79- for i in range (cycles ):
80- if left_to_enable > tb .master_stream_in .data_width :
81- byte_enable = 2 ** tb .master_stream_in .data_width - 1
82- """setting all bytes of byte enable to 1"""
89+ cycles = ceildiv (bus_width = tb .request_stream_in .data_width , transaction_len = len (offset_transaction ))
8390
84- left_to_enable -= tb .master_stream_in .data_width
91+ for i in range (cycles ):
92+ data = offset_transaction [i * tb .request_stream_in .data_width :(i + 1 )* tb .request_stream_in .data_width ]
8593
86- else :
87- byte_enable = 2 ** left_to_enable - 1
94+ be_slice = BinaryValue ( byte_enable . binstr [ i * tb . request_stream_in . data_width :( i + 1 ) * tb . request_stream_in . data_width ][:: - 1 ], bigEndian = False ). integer
95+ enabled_data = filter_bytes_by_bitmask ( data , be_slice )
8896
89- byte_enable = 15 if testcase == 0 else byte_enable
97+ if len (enabled_data ) == 0 :
98+ continue
9099
91- tb .model ((int .from_bytes (transaction [0 :tb .master_stream_in .addr_width ], 'little' ) + i * tb .master_stream_in .addr_width , int .from_bytes (transaction [i * tb .master_stream_in .data_width :(i + 1 ) * tb .master_stream_in .data_width ], 'little' ), byte_enable ), testcase )
100+ test_trans = MiTransaction ()
101+ test_trans .trans_type = request_type
102+ test_trans .addr = addr + i * tb .request_stream_in .addr_width
103+ test_trans .data = int .from_bytes (enabled_data , 'little' )
104+ test_trans .be = be_slice
105+ tb .model (test_trans )
106+ item_count += 1
92107
93- if testcase == 0 :
94- """read test"""
95- cocotb . log . debug ( f"generated transaction: { transaction . hex () } " )
96- tb . master_stream_in . append (( "rd" , transaction ))
97- tb . slave_stream_in . append (( "rd" , transaction ) )
108+ request_trans = MiRequestTransaction ()
109+ request_trans . trans_type = request_type
110+ request_trans . addr = start_addr
111+ request_trans . data = transaction
112+ request_trans . data_len = len ( transaction )
98113
99- else :
100- """write test"""
101- cocotb .log .debug (f"generated transaction: { transaction .hex ()} " )
102- tb .master_stream_in .append (("wr" , transaction ))
103- tb .slave_stream_in .append (("wr" , transaction ))
114+ response_trans = MiResponseTransaction ()
115+ response_trans .trans_type = request_type
116+ response_trans .data = offset_transaction
117+ response_trans .be = byte_enable .integer
104118
105- last_num = 0
119+ cocotb .log .debug (f"generated transaction: { transaction .hex ()} " )
120+ tb .request_stream_in .append (request_trans )
121+ tb .response_stream_in .append (response_trans )
106122
107- stream_out = tb . slave_stream_out if testcase == 0 else tb . master_stream_out
108- transaction_type = "read" if testcase == 0 else "write"
123+ last_num = 0
124+ stream_out_item_cnt = tb . response_proxy . item_cnt + tb . request_proxy . item_cnt
109125
110- while stream_out .item_cnt < item_count :
111- if stream_out .item_cnt // 1000 > last_num :
112- last_num = stream_out .item_cnt // 1000
113- cocotb .log .info (f"Number of { transaction_type } transactions processed: { stream_out .item_cnt } /{ item_count } " )
114- await ClockCycles (dut .CLK , 100 )
126+ while stream_out_item_cnt < item_count :
127+ if stream_out_item_cnt // 1000 > last_num :
128+ last_num = stream_out_item_cnt // 1000
129+ cocotb .log .info (f"Number of transactions processed: { stream_out_item_cnt } /{ item_count } " )
130+ await ClockCycles (dut .CLK , 100 )
131+ stream_out_item_cnt = tb .response_proxy .item_cnt + tb .request_proxy .item_cnt
115132
116133 raise tb .scoreboard .result
0 commit comments