7
7
import cocotb
8
8
from cocotb .clock import Clock
9
9
from 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
13
13
from cocotbext .ofm .ver .generators import random_packets
14
+ from cocotbext .ofm .utils .math import ceildiv
14
15
from 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
16
20
17
21
import itertools
22
+ from random import choice , randint
18
23
19
24
20
25
class testbench ():
21
26
def __init__ (self , dut , debug = False ):
22
27
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 )
27
34
28
35
self .backpressure = BitDriver (dut .OUT_ARDY , dut .CLK )
29
36
30
- # Create a scoreboard on the master_stream_out bus
37
+ # Create a scoreboard on the response_stream_out bus
31
38
self .pkts_sent = 0
32
- self .expected_output_master = []
33
- self .expected_output_slave = []
39
+ self .expected_output = []
34
40
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 )
37
43
38
44
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 )
41
47
42
- def model (self , transaction : bytes , testcase : int ):
48
+ def model (self , test_trans : MiTransaction ):
43
49
"""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 )
48
50
51
+ self .expected_output .append (test_trans )
49
52
self .pkts_sent += 1
50
53
51
54
async def reset (self ):
@@ -59,58 +62,72 @@ async def reset(self):
59
62
async def run_test (dut , pkt_count : int = 1000 , item_width_min : int = 1 , item_width_max : int = 32 ):
60
63
# Start clock generator
61
64
cocotb .start_soon (Clock (dut .CLK , 5 , units = 'ns' ).start ())
62
- tb = testbench (dut )
65
+ tb = testbench (dut , debug = False )
63
66
await tb .reset ()
64
67
65
68
tb .backpressure .start ((1 , i % 5 ) for i in itertools .count ())
66
69
67
- for testcase in range ( 2 ):
68
- """two test cases - read = 0, write = 1"""
70
+ item_count = 0
71
+ trans_cntr = 0
69
72
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 )
71
77
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 )
74
81
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
76
84
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
78
88
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 ))
83
90
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 ]
85
93
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 )
88
96
89
- byte_enable = 15 if testcase == 0 else byte_enable
97
+ if len (enabled_data ) == 0 :
98
+ continue
90
99
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
92
107
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 )
98
113
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
104
118
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 )
106
122
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
109
125
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
115
132
116
133
raise tb .scoreboard .result
0 commit comments