@@ -46,7 +46,39 @@ module axi_sim_mem #(
46
46
// / AXI4 request struct
47
47
input axi_req_t axi_req_i,
48
48
// / AXI4 response struct
49
- output axi_rsp_t axi_rsp_o
49
+ output axi_rsp_t axi_rsp_o,
50
+ // / Memory monitor write valid. All `mon_w_*` outputs are only valid if this signal is high.
51
+ // / A write to the memory is visible on the `mon_w_*` outputs in the clock cycle after it has
52
+ // / happened.
53
+ output logic mon_w_valid_o,
54
+ // / Memory monitor write address
55
+ output logic [AddrWidth- 1 : 0 ] mon_w_addr_o,
56
+ // / Memory monitor write data
57
+ output logic [DataWidth- 1 : 0 ] mon_w_data_o,
58
+ // / Memory monitor write ID
59
+ output logic [IdWidth- 1 : 0 ] mon_w_id_o,
60
+ // / Memory monitor write user
61
+ output logic [UserWidth- 1 : 0 ] mon_w_user_o,
62
+ // / Memory monitor write beat count
63
+ output axi_pkg :: len_t mon_w_beat_count_o,
64
+ // / Memory monitor write last
65
+ output logic mon_w_last_o,
66
+ // / Memory monitor read valid. All `mon_r_*` outputs are only valid if this signal is high.
67
+ // / A read from the memory is visible on the `mon_w_*` outputs in the clock cycle after it has
68
+ // / happened.
69
+ output logic mon_r_valid_o,
70
+ // / Memory monitor read address
71
+ output logic [AddrWidth- 1 : 0 ] mon_r_addr_o,
72
+ // / Memory monitor read data
73
+ output logic [DataWidth- 1 : 0 ] mon_r_data_o,
74
+ // / Memory monitor read ID
75
+ output logic [IdWidth- 1 : 0 ] mon_r_id_o,
76
+ // / Memory monitor read user
77
+ output logic [UserWidth- 1 : 0 ] mon_r_user_o,
78
+ // / Memory monitor read beat count
79
+ output axi_pkg :: len_t mon_r_beat_count_o,
80
+ // / Memory monitor read last
81
+ output logic mon_r_last_o
50
82
);
51
83
52
84
localparam int unsigned StrbWidth = DataWidth / 8 ;
@@ -61,6 +93,17 @@ module axi_sim_mem #(
61
93
`AXI_TYPEDEF_AR_CHAN_T (ar_t, addr_t, id_t, user_t)
62
94
`AXI_TYPEDEF_R_CHAN_T (r_t, data_t, id_t, user_t)
63
95
96
+ typedef struct packed {
97
+ logic valid;
98
+ logic [AddrWidth- 1 : 0 ] addr;
99
+ logic [DataWidth- 1 : 0 ] data;
100
+ logic [IdWidth- 1 : 0 ] id;
101
+ logic [UserWidth- 1 : 0 ] user;
102
+ axi_pkg :: len_t beat_count;
103
+ logic last;
104
+ } monitor_t ;
105
+
106
+ monitor_t mon_w, mon_r;
64
107
logic [7 : 0 ] mem[addr_t];
65
108
66
109
initial begin
@@ -69,6 +112,9 @@ module axi_sim_mem #(
69
112
automatic b_t b_queue[$];
70
113
automatic shortint unsigned r_cnt = 0 , w_cnt = 0 ;
71
114
axi_rsp_o = '0 ;
115
+ // Monitor interface
116
+ mon_w = '0 ;
117
+ mon_r = '0 ;
72
118
wait (rst_ni);
73
119
fork
74
120
// AW
@@ -87,6 +133,7 @@ module axi_sim_mem #(
87
133
@ (posedge clk_i);
88
134
# (ApplDelay);
89
135
axi_rsp_o.w_ready = 1'b0 ;
136
+ mon_w = '0 ;
90
137
if (aw_queue.size () != 0 ) begin
91
138
axi_rsp_o.w_ready = 1'b1 ;
92
139
# (AcqDelay - ApplDelay);
@@ -96,6 +143,12 @@ module axi_sim_mem #(
96
143
automatic axi_pkg :: size_t size = aw_queue[0 ].size;
97
144
automatic addr_t addr = axi_pkg :: beat_addr (aw_queue[0 ].addr, size, len, burst,
98
145
w_cnt);
146
+ mon_w.valid = 1'b1 ;
147
+ mon_w.addr = addr;
148
+ mon_w.data = axi_req_i.w.data;
149
+ mon_w.id = aw_queue[0 ].id;
150
+ mon_w.user = aw_queue[0 ].user;
151
+ mon_w.beat_count = w_cnt;
99
152
for (shortint unsigned
100
153
i_byte = axi_pkg :: beat_lower_byte (addr, size, len, burst, StrbWidth, w_cnt);
101
154
i_byte <= axi_pkg :: beat_upper_byte (addr, size, len, burst, StrbWidth, w_cnt);
@@ -112,6 +165,7 @@ module axi_sim_mem #(
112
165
b_beat.resp = axi_pkg :: RESP_OKAY ;
113
166
b_queue.push_back (b_beat);
114
167
w_cnt = 0 ;
168
+ mon_w.last = 1'b1 ;
115
169
void '(aw_queue.pop_front ());
116
170
end else begin
117
171
assert (! axi_req_i.w.last) else $error (" Did not expect last beat of W burst!" );
@@ -150,6 +204,7 @@ module axi_sim_mem #(
150
204
@ (posedge clk_i);
151
205
# (ApplDelay);
152
206
axi_rsp_o.r_valid = 1'b0 ;
207
+ mon_r = '0 ;
153
208
if (ar_queue.size () != 0 ) begin
154
209
automatic axi_pkg :: burst_t burst = ar_queue[0 ].burst;
155
210
automatic axi_pkg :: len_t len = ar_queue[0 ].len;
@@ -176,13 +231,21 @@ module axi_sim_mem #(
176
231
end
177
232
if (r_cnt == ar_queue[0 ].len) begin
178
233
r_beat.last = 1'b1 ;
234
+ mon_r.last = 1'b1 ;
179
235
end
180
236
axi_rsp_o.r = r_beat;
181
237
axi_rsp_o.r_valid = 1'b1 ;
238
+ mon_r.valid = 1'b1 ;
239
+ mon_r.addr = addr;
240
+ mon_r.data = r_beat.data;
241
+ mon_r.id = r_beat.id;
242
+ mon_r.user = r_beat.user;
243
+ mon_r.beat_count = r_cnt;
182
244
# (AcqDelay - ApplDelay);
183
245
while (! axi_req_i.r_ready) begin
184
246
@ (posedge clk_i);
185
247
# (AcqDelay);
248
+ mon_r = '0 ;
186
249
end
187
250
if (r_beat.last) begin
188
251
r_cnt = 0 ;
@@ -195,6 +258,46 @@ module axi_sim_mem #(
195
258
join
196
259
end
197
260
261
+ // Assign the monitor output in the next clock cycle. Rationale: We only know whether we are
262
+ // writing until after `AcqDelay`. This means we could only provide the monitoring output for
263
+ // writes after `AcqDelay` in the same cycle, which is incompatible with ATI timing. Thus, we
264
+ // provide the monitoring output for writes (and for uniformity also for reads) in the next clock
265
+ // cycle.
266
+ initial begin
267
+ mon_w_valid_o = '0 ;
268
+ mon_w_addr_o = '0 ;
269
+ mon_w_data_o = '0 ;
270
+ mon_w_id_o = '0 ;
271
+ mon_w_user_o = '0 ;
272
+ mon_w_beat_count_o = '0 ;
273
+ mon_w_last_o = '0 ;
274
+ mon_r_valid_o = '0 ;
275
+ mon_r_addr_o = '0 ;
276
+ mon_r_data_o = '0 ;
277
+ mon_r_id_o = '0 ;
278
+ mon_r_user_o = '0 ;
279
+ mon_r_beat_count_o = '0 ;
280
+ mon_r_last_o = '0 ;
281
+ wait (rst_ni);
282
+ forever begin
283
+ @ (posedge clk_i);
284
+ mon_w_valid_o <= # (ApplDelay) mon_w.valid;
285
+ mon_w_addr_o <= # (ApplDelay) mon_w.addr;
286
+ mon_w_data_o <= # (ApplDelay) mon_w.data;
287
+ mon_w_id_o <= # (ApplDelay) mon_w.id;
288
+ mon_w_user_o <= # (ApplDelay) mon_w.user;
289
+ mon_w_beat_count_o <= # (ApplDelay) mon_w.beat_count;
290
+ mon_w_last_o <= # (ApplDelay) mon_w.last;
291
+ mon_r_valid_o <= # (ApplDelay) mon_r.valid;
292
+ mon_r_addr_o <= # (ApplDelay) mon_r.addr;
293
+ mon_r_data_o <= # (ApplDelay) mon_r.data;
294
+ mon_r_id_o <= # (ApplDelay) mon_r.id;
295
+ mon_r_user_o <= # (ApplDelay) mon_r.user;
296
+ mon_r_beat_count_o <= # (ApplDelay) mon_r.beat_count;
297
+ mon_r_last_o <= # (ApplDelay) mon_r.last;
298
+ end
299
+ end
300
+
198
301
// Parameter Assertions
199
302
initial begin
200
303
assert (AddrWidth != 0 ) else $fatal (" AddrWidth must be non-zero!" , 1 );
@@ -220,9 +323,23 @@ module axi_sim_mem_intf #(
220
323
parameter time APPL_DELAY = 0ps ,
221
324
parameter time ACQ_DELAY = 0ps
222
325
) (
223
- input logic clk_i,
224
- input logic rst_ni,
225
- AXI_BUS .Slave axi_slv
326
+ input logic clk_i,
327
+ input logic rst_ni,
328
+ AXI_BUS .Slave axi_slv,
329
+ output logic mon_w_valid_o,
330
+ output logic [AXI_ADDR_WIDTH - 1 : 0 ] mon_w_addr_o,
331
+ output logic [AXI_DATA_WIDTH - 1 : 0 ] mon_w_data_o,
332
+ output logic [AXI_ID_WIDTH - 1 : 0 ] mon_w_id_o,
333
+ output logic [AXI_USER_WIDTH - 1 : 0 ] mon_w_user_o,
334
+ output axi_pkg :: len_t mon_w_beat_count_o,
335
+ output logic mon_w_last_o,
336
+ output logic mon_r_valid_o,
337
+ output logic [AXI_ADDR_WIDTH - 1 : 0 ] mon_r_addr_o,
338
+ output logic [AXI_DATA_WIDTH - 1 : 0 ] mon_r_data_o,
339
+ output logic [AXI_ID_WIDTH - 1 : 0 ] mon_r_id_o,
340
+ output logic [AXI_USER_WIDTH - 1 : 0 ] mon_r_user_o,
341
+ output axi_pkg :: len_t mon_r_beat_count_o,
342
+ output logic mon_r_last_o
226
343
);
227
344
228
345
typedef logic [AXI_ADDR_WIDTH - 1 : 0 ] axi_addr_t ;
@@ -251,8 +368,22 @@ module axi_sim_mem_intf #(
251
368
) i_sim_mem (
252
369
.clk_i,
253
370
.rst_ni,
254
- .axi_req_i (axi_req),
255
- .axi_rsp_o (axi_rsp)
371
+ .axi_req_i (axi_req),
372
+ .axi_rsp_o (axi_rsp),
373
+ .mon_w_valid_o,
374
+ .mon_w_addr_o,
375
+ .mon_w_data_o,
376
+ .mon_w_id_o,
377
+ .mon_w_user_o,
378
+ .mon_w_beat_count_o,
379
+ .mon_w_last_o,
380
+ .mon_r_valid_o,
381
+ .mon_r_addr_o,
382
+ .mon_r_data_o,
383
+ .mon_r_id_o,
384
+ .mon_r_user_o,
385
+ .mon_r_beat_count_o,
386
+ .mon_r_last_o
256
387
);
257
388
258
389
endmodule
0 commit comments