8
8
9
9
@cocotb .test (timeout_time = 50 , timeout_unit = 'ms' )
10
10
async def transmit (dut ):
11
- """TX with randomized payload / clock skew / inter-TX delay."""
11
+ """TX with randomized payload / clock frequency shift / inter-TX delay."""
12
12
13
13
# 50 Mhz clock
14
14
cocotb .start_soon (Clock (dut .clk , 20 , units = 'ns' ).start ())
15
15
16
- # reset
17
- dut .tx_reset .value = 1
18
- await Timer (1 , units = "ms" )
19
- dut .tx_reset .value = 0
20
- await Timer (1 , units = "ms" )
16
+ await check_tx_reset (dut )
21
17
22
- # run 100 randomized tests
18
+ # carry out 100 transmissions
23
19
for count in range (100 ):
24
- # check TX=1 and ready=1
25
- assert dut .uart_tx == 1
26
- assert dut .tx_ready .value == 1
27
-
28
- # prepare random test data
29
- TEST_BYTE = random .randint (0 ,255 ) # 0xA5
30
- TEST_BITS_LSB = [(TEST_BYTE >> s ) & 1 for s in range (8 )]
31
-
32
- # set data value and then start TX
33
- dut .tx_data .value = TEST_BYTE
34
- await Timer (100 + random .randint (0 , 1000 ), units = "ns" )
35
- dut .tx_valid .value = 1
36
-
37
- # wait for TX->0 transition, check TX=0 and ready=0
38
- await Edge (dut .uart_tx )
39
- assert dut .uart_tx .value == 0
40
- assert dut .tx_ready .value == 0
41
-
42
- # set valid back to 0
43
- dut .tx_valid .value = 0
20
+ # randomized payload
21
+ TEST_BYTE = random .randint (0 ,255 )
44
22
45
- # randomized RX frequency skew (+/- 2%)
46
- skew = 1.0 + (random .random () - 0.5 ) / 50 * 2
23
+ # randomized baud multiplier (+/- 2%)
24
+ baud_mult = 1.0 + (random .random () - 0.5 ) / 50 * 2
47
25
48
- # wait 1/2 bit
49
- await Timer (int (0.5 / 115200. * skew * 1e12 ), units = "ps" )
50
-
51
- # check for start bit (0), 8 data bits, stop bit (1)
52
- for expected_bit in [0 ] + TEST_BITS_LSB + [1 ]:
53
- assert dut .uart_tx .value == expected_bit
54
- await Timer (int (1 / 115200. * skew * 1e12 ), units = "ps" )
55
-
56
- assert dut .tx_ready .value == 1
26
+ await check_tx (dut , TEST_BYTE , 115200 , baud_mult )
57
27
58
28
# randomized inter-TX interval
59
- if random .random () > 0.2 :
60
- await Timer (random .randint (1 ,5 ), units = 'us ' )
29
+ if random .random () > 0.1 :
30
+ await Timer (random .randint (1 ,2000 ), units = 'ns ' )
61
31
62
32
63
33
@cocotb .test (timeout_time = 50 , timeout_unit = 'ms' )
64
34
async def receive1 (dut ):
65
- """RX with randomized payload / clock skew / inter-TX delay."""
35
+ """RX with randomized payload / clock frequency shift / inter-TX delay."""
66
36
67
37
# 50 Mhz clock
68
38
cocotb .start_soon (Clock (dut .clk , 20 , units = 'ns' ).start ())
69
39
70
- # drive input high
71
- dut .uart_rx .value = 1
72
-
73
40
# reset
74
- dut .rx_reset .value = 1
75
- await Timer (1 , units = "ms" )
76
- dut .rx_reset .value = 0
77
- await Timer (1 , units = "ms" )
41
+ await check_rx_reset (dut )
78
42
79
- # check valid=0, err=0
80
- assert dut .rx_valid .value == 0
81
- assert dut .rx_error .value == 0
82
-
83
43
# run 100 randomized tests
84
44
for count in range (100 ):
85
- dut .rx_ready .value = 0
45
+ # randomized payload
46
+ TEST_BYTE = random .randint (0 ,255 )
86
47
87
- # random delay
88
- await Timer (100 + random .randint (0 , 1000 ), units = "ns" )
89
- assert dut .rx_valid .value == 0
48
+ # randomized baud multiplier (+/- 2%)
49
+ baud_mult = 1.0 + (random .random () - 0.5 ) / 50 * 2
90
50
91
- # prepare random test data
92
- TEST_BYTE = random .randint (0 ,255 ) # 0xA5
93
- TEST_BITS_LSB = [(TEST_BYTE >> s ) & 1 for s in range (8 )]
94
-
95
- # randomized TX frequency skew (+/- 2%)
96
- skew = 1.0 + (random .random () - 0.5 ) / 50 * 2
51
+ await check_rx (dut , TEST_BYTE , 115200 , baud_mult )
97
52
98
- # send start bit (0), 8 data bits, stop bit (1)
99
- for tx_bit in [0 ] + TEST_BITS_LSB + [1 ]:
100
- dut .uart_rx .value = tx_bit
101
- await Timer (int (1 / 115200. * skew * 1e12 ), units = "ps" )
53
+ # randomized delay
54
+ await Timer (random .randint (500 ,2000 ), units = 'ns' )
102
55
103
- # random delay
104
- await Timer (100 + random .randint (0 , 1000 ), units = "ns" )
105
- assert dut .rx_valid .value == 1
106
56
107
- dut .rx_ready .value = 1
57
+ @cocotb .test (timeout_time = 50 , timeout_unit = 'ms' )
58
+ async def receive2 (dut ):
59
+ """Continuous RX with randomized payload."""
108
60
109
- # wait for valid transition
110
- await Edge (dut .rx_valid )
111
- assert dut .rx_valid .value == 0
61
+ # 50 Mhz clock
62
+ cocotb .start_soon (Clock (dut .clk , 20 , units = 'ns' ).start ())
112
63
113
- # check payload and valid/error/overflow flags
114
- assert dut .rx_data .value == TEST_BYTE
115
- assert dut .rx_error .value == 0
116
- assert dut .rx_overrun .value == 0
64
+ # reset
65
+ await check_tx_reset (dut )
117
66
118
- # randomized delay
119
- await Timer (random .randint (1 ,5 ), units = 'us' )
67
+ # run 100 randomized tests
68
+ for count in range (100 ):
69
+ # randomized payload
70
+ TEST_BYTE = random .randint (0 ,255 )
71
+ await check_rx (dut , TEST_BYTE , 115200 , 1.0 )
120
72
121
73
122
74
@cocotb .test (timeout_time = 50 , timeout_unit = 'ms' )
123
- async def receive2 (dut ):
124
- """Continuous RX with randomized payload / frequency skew ."""
75
+ async def receive3 (dut ):
76
+ """Continuous RX with randomized payload / clock frequency shift ."""
125
77
126
78
# 50 Mhz clock
127
79
cocotb .start_soon (Clock (dut .clk , 20 , units = 'ns' ).start ())
128
80
129
- # drive input high
130
- dut .uart_rx .value = 1
131
-
132
81
# reset
133
- dut .rx_reset .value = 1
134
- await Timer (1 , units = "ms" )
135
- dut .rx_reset .value = 0
136
- await Timer (1 , units = "ms" )
137
-
138
- # check valid=0, err=0
139
- assert dut .rx_valid .value == 0
140
- assert dut .rx_error .value == 0
141
-
142
- dut .rx_ready .value = 1
82
+ await check_tx_reset (dut )
143
83
144
84
# run 100 randomized tests
145
85
for count in range (100 ):
146
- # prepare random test data
147
- TEST_BYTE = random .randint (0 ,255 ) # 0xA5
148
- TEST_BITS_LSB = [(TEST_BYTE >> s ) & 1 for s in range (8 )]
86
+ # randomized payload
87
+ TEST_BYTE = random .randint (0 ,255 )
149
88
150
- # randomized TX frequency skew (+/- 2%)
151
- skew = 1.0 + (random .random () - 0.5 ) / 50 * 2
89
+ # randomized baud multiplier (+/- 2%)
90
+ baud_mult = 1.0 + (random .random () - 0.5 ) / 50 * 2
152
91
153
- # send start bit (0), 8 data bits, stop bit (1)
154
- for tx_bit in [0 ] + TEST_BITS_LSB + [1 ]:
155
- dut .uart_rx .value = tx_bit
156
- await Timer (int (1 / 115200. * skew * 1e12 ), units = "ps" )
157
-
158
- # check payload and valid/error/overflow flags
159
- assert dut .rx_data .value == TEST_BYTE
160
- assert dut .rx_error .value == 0
161
- assert dut .rx_overrun .value == 0
92
+ await check_rx (dut , TEST_BYTE , 115200 , baud_mult )
162
93
163
94
164
95
@cocotb .test (timeout_time = 50 , timeout_unit = 'ms' )
165
- async def receive3 (dut ):
96
+ async def receive4 (dut ):
166
97
"""RX overrun."""
167
98
168
99
# 50 Mhz clock
169
100
cocotb .start_soon (Clock (dut .clk , 20 , units = 'ns' ).start ())
170
101
171
- # drive input high
172
- dut .uart_rx .value = 1
173
-
174
102
# reset
175
- dut .rx_reset .value = 1
176
- await Timer (1 , units = "ms" )
177
- dut .rx_reset .value = 0
178
- await Timer (1 , units = "ms" )
179
-
180
- # check valid=0, err=0
181
- assert dut .rx_valid .value == 0
182
- assert dut .rx_error .value == 0
103
+ await check_tx_reset (dut )
183
104
105
+ # set RX ready low, and keep it low...
184
106
dut .rx_ready .value = 0
185
107
108
+ # ...across 2 RX operations, until the received overruns
186
109
for count in range (2 ):
187
110
# prepare random test data
188
- TEST_BYTE = random .randint (0 ,255 ) # 0xA5
111
+ TEST_BYTE = random .randint (0 ,255 )
189
112
TEST_BITS_LSB = [(TEST_BYTE >> s ) & 1 for s in range (8 )]
190
113
191
114
# send start bit (0), 8 data bits, stop bit (1)
@@ -194,12 +117,104 @@ async def receive3(dut):
194
117
await Timer (int (1 / 115200. * 1e12 ), units = "ps" )
195
118
196
119
# check payload and valid/error/overflow flags
120
+ assert dut .rx_valid .value == 1
121
+ assert dut .rx_error .value == 0
197
122
if (count == 0 ):
198
123
TEST_BYTE_PREV = TEST_BYTE
199
124
assert dut .rx_data .value == TEST_BYTE
200
- assert dut .rx_error .value == 0
201
125
assert dut .rx_overrun .value == 0
202
126
else :
203
127
assert dut .rx_data .value == TEST_BYTE_PREV
204
- assert dut .rx_error .value == 0
205
128
assert dut .rx_overrun .value == 1
129
+
130
+
131
+
132
+ # --- HELPER FUNCTIONS ---
133
+
134
+ async def check_tx_reset (dut ):
135
+ # reset
136
+ dut .tx_reset .value = 1
137
+ await Timer (1 , units = "ms" )
138
+ dut .tx_reset .value = 0
139
+ await Timer (1 , units = "ms" )
140
+
141
+ assert dut .tx_ready .value == 1
142
+
143
+
144
+ async def check_rx_reset (dut ):
145
+ # drive input high
146
+ dut .uart_rx .value = 1
147
+
148
+ # reset
149
+ dut .rx_reset .value = 1
150
+ await Timer (1 , units = "ms" )
151
+ dut .rx_reset .value = 0
152
+ await Timer (1 , units = "ms" )
153
+
154
+ assert dut .rx_valid .value == 0
155
+ assert dut .rx_error .value == 0
156
+ assert dut .rx_overrun .value == 0
157
+
158
+
159
+ async def check_tx (dut , data , baud , baud_mult ):
160
+ # check TX=1 and ready=1
161
+ assert dut .uart_tx == 1
162
+ assert dut .tx_ready .value == 1
163
+
164
+ # prepare random test data
165
+ TEST_BITS_LSB = [(data >> s ) & 1 for s in range (8 )]
166
+
167
+ # set data value and then start TX
168
+ dut .tx_data .value = data
169
+ await Timer (random .randint (100 , 500 ), units = "ns" )
170
+ dut .tx_valid .value = 1
171
+
172
+ # wait for TX->0 transition, check TX=0 and ready=0
173
+ await Edge (dut .uart_tx )
174
+ assert dut .uart_tx .value == 0
175
+ assert dut .tx_ready .value == 0
176
+
177
+ # set valid back to 0
178
+ dut .tx_valid .value = 0
179
+
180
+ # wait 1/2 bit
181
+ await Timer (int (0.5 / baud * baud_mult * 1e12 ), units = "ps" )
182
+
183
+ # check for start bit (0), 8 data bits, stop bit (1)
184
+ for expected_bit in [0 ] + TEST_BITS_LSB + [1 ]:
185
+ assert dut .uart_tx .value == expected_bit
186
+ await Timer (int (1.0 / baud * baud_mult * 1e12 ), units = "ps" )
187
+
188
+ assert dut .tx_ready .value == 1
189
+
190
+
191
+ async def check_rx (dut , data , baud , baud_mult ):
192
+ dut .rx_ready .value = 0
193
+
194
+ # random delay
195
+ await Timer (100 + random .randint (100 , 500 ), units = "ns" )
196
+ assert dut .rx_valid .value == 0
197
+
198
+ # prepare random test data
199
+ TEST_BITS_LSB = [(data >> s ) & 1 for s in range (8 )]
200
+
201
+ # send start bit (0), 8 data bits, stop bit (1)
202
+ for tx_bit in [0 ] + TEST_BITS_LSB + [1 ]:
203
+ dut .uart_rx .value = tx_bit
204
+ await Timer (int (1 / baud * baud_mult * 1e12 ), units = "ps" )
205
+
206
+ # random delay
207
+ await Timer (100 + random .randint (100 , 500 ), units = "ns" )
208
+ assert dut .rx_valid .value == 1
209
+
210
+ dut .rx_ready .value = 1
211
+
212
+ # wait for valid transition
213
+ await Edge (dut .rx_valid )
214
+ assert dut .rx_valid .value == 0
215
+
216
+ # check payload and valid/error/overflow flags
217
+ assert dut .rx_data .value == data
218
+ assert dut .rx_error .value == 0
219
+ assert dut .rx_overrun .value == 0
220
+
0 commit comments