-
Notifications
You must be signed in to change notification settings - Fork 7
/
axi_adapter.sv
636 lines (561 loc) · 21.4 KB
/
axi_adapter.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
/* Copyright 2018 ETH Zurich and University of Bologna.
* Copyright and related rights are licensed under the Solderpad Hardware
* License, Version 0.51 (the “License”); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
* or agreed to in writing, software, hardware and materials distributed under
* this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* File: axi_adapter.sv
* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
* Date: 1.8.2018
*
* Description: Manages communication with the AXI Bus
*/
//import std_cache_pkg::*;
module axi_adapter #(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
parameter int unsigned DATA_WIDTH = 256,
parameter logic CRITICAL_WORD_FIRST = 0, // the AXI subsystem needs to support wrapping reads for this feature
parameter int unsigned CACHELINE_BYTE_OFFSET = 8,
parameter int unsigned MAX_OUTSTANDING_AW = 0, // Actual number of in-flight store transactions allowed is (MAX_OUTSTANDING_AW+1)
parameter logic AXI_ACE = 0, // Support AMBA ACE
parameter type axi_req_t = logic,
parameter type axi_rsp_t = logic
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
output logic busy_o,
input logic req_i,
input ariane_pkg::ad_req_t type_i,
input ace_pkg::ace_trs_t trans_type_i,
input ariane_pkg::amo_t amo_i,
output logic gnt_o,
input logic [riscv::XLEN-1:0] addr_i,
input logic we_i,
input logic [(DATA_WIDTH/CVA6Cfg.AxiDataWidth)-1:0][CVA6Cfg.AxiDataWidth-1:0] wdata_i,
input logic [(DATA_WIDTH/CVA6Cfg.AxiDataWidth)-1:0][(CVA6Cfg.AxiDataWidth/8)-1:0] be_i,
input logic [1:0] size_i,
input logic [CVA6Cfg.AxiIdWidth-1:0] id_i,
output logic dirty_o,
output logic shared_o,
// read port
output logic valid_o,
output logic [(DATA_WIDTH/CVA6Cfg.AxiDataWidth)-1:0][CVA6Cfg.AxiDataWidth-1:0] rdata_o,
output logic [CVA6Cfg.AxiIdWidth-1:0] id_o,
// critical word - read port
output logic [CVA6Cfg.AxiDataWidth-1:0] critical_word_o,
output logic critical_word_valid_o,
// AXI port
output axi_req_t axi_req_o,
input axi_rsp_t axi_resp_i
);
localparam BURST_SIZE = (DATA_WIDTH / CVA6Cfg.AxiDataWidth) - 1;
localparam ADDR_INDEX = ($clog2(
DATA_WIDTH / CVA6Cfg.AxiDataWidth
) > 0) ? $clog2(
DATA_WIDTH / CVA6Cfg.AxiDataWidth
) : 1;
localparam MAX_OUTSTANDING_AW_CNT_WIDTH = $clog2(
MAX_OUTSTANDING_AW + 1
) > 0 ? $clog2(
MAX_OUTSTANDING_AW + 1
) : 1;
typedef logic [MAX_OUTSTANDING_AW_CNT_WIDTH-1:0] outstanding_aw_cnt_t;
enum logic [3:0] {
IDLE,
WAIT_B_VALID,
WAIT_AW_READY,
WAIT_LAST_W_READY,
WAIT_LAST_W_READY_AW_READY,
WAIT_AW_READY_BURST,
WAIT_R_VALID,
WAIT_R_VALID_MULTIPLE,
COMPLETE_READ,
WAIT_AMO_R_VALID
}
state_q, state_d;
// counter for AXI transfers
logic [ADDR_INDEX-1:0] cnt_d, cnt_q;
logic [(DATA_WIDTH/CVA6Cfg.AxiDataWidth)-1:0][CVA6Cfg.AxiDataWidth-1:0]
cache_line_d, cache_line_q;
// save the address for a read, as we allow for non-cacheline aligned accesses
logic [(DATA_WIDTH/CVA6Cfg.AxiDataWidth)-1:0] addr_offset_d, addr_offset_q;
logic [CVA6Cfg.AxiIdWidth-1:0] id_d, id_q;
logic [ADDR_INDEX-1:0] index;
// save the atomic operation and size
ariane_pkg::amo_t amo_d, amo_q;
logic [1:0] size_d, size_q;
// outstanding write transactions counter
outstanding_aw_cnt_t outstanding_aw_cnt_q, outstanding_aw_cnt_d;
logic any_outstanding_aw;
assign any_outstanding_aw = outstanding_aw_cnt_q != '0;
// Busy if we're not idle
assign busy_o = state_q != IDLE;
logic dirty, dirty_d, dirty_q;
logic shared, shared_d, shared_q;
if (AXI_ACE) begin
assign dirty = axi_resp_i.r.resp[2];
assign shared = axi_resp_i.r.resp[3];
end else begin
assign dirty = 1'b0;
assign shared = 1'b0;
end
always_comb begin : axi_fsm
// Default assignments
axi_req_o.aw_valid = 1'b0;
// Cast to AXI address width
axi_req_o.aw.addr = addr_i;
axi_req_o.aw.prot = 3'b0;
axi_req_o.aw.region = 4'b0;
axi_req_o.aw.len = 8'b0;
axi_req_o.aw.size = {1'b0, size_i}; // 1, 2, 4 or 8 bytes
axi_req_o.aw.burst = axi_pkg::BURST_INCR; // Use BURST_INCR for AXI regular transaction
axi_req_o.aw.lock = 1'b0;
axi_req_o.aw.cache = axi_pkg::CACHE_MODIFIABLE;
axi_req_o.aw.qos = 4'b0;
axi_req_o.aw.id = id_i;
axi_req_o.aw.atop = atop_from_amo(amo_i);
axi_req_o.aw.user = '0;
axi_req_o.ar_valid = 1'b0;
// Cast to AXI address width
axi_req_o.ar.addr = addr_i;
// in case of a single request or wrapping transfer we can simply begin at the address, if we want to request a cache-line
// with an incremental transfer we need to output the corresponding base address of the cache line
if (!CRITICAL_WORD_FIRST && type_i != ariane_pkg::SINGLE_REQ) begin
axi_req_o.ar.addr[CACHELINE_BYTE_OFFSET-1:0] = '0;
end
axi_req_o.ar.prot = 3'b0;
axi_req_o.ar.region = 4'b0;
axi_req_o.ar.len = 8'b0;
axi_req_o.ar.size = {1'b0, size_i}; // 1, 2, 4 or 8 bytes
axi_req_o.ar.burst = (CRITICAL_WORD_FIRST ? axi_pkg::BURST_WRAP : axi_pkg::BURST_INCR); // wrapping transfer in case of a critical word first strategy
axi_req_o.ar.lock = 1'b0;
axi_req_o.ar.cache = axi_pkg::CACHE_MODIFIABLE;
axi_req_o.ar.qos = 4'b0;
axi_req_o.ar.id = id_i;
axi_req_o.ar.user = '0;
axi_req_o.w_valid = 1'b0;
axi_req_o.w.data = wdata_i[0];
axi_req_o.w.strb = be_i[0];
axi_req_o.w.last = 1'b0;
axi_req_o.w.user = '0;
axi_req_o.b_ready = 1'b0;
axi_req_o.r_ready = 1'b0;
gnt_o = 1'b0;
valid_o = 1'b0;
id_o = axi_resp_i.r.id;
critical_word_o = axi_resp_i.r.data;
critical_word_valid_o = 1'b0;
rdata_o = cache_line_q;
dirty_o = dirty_q;
shared_o = shared_q;
state_d = state_q;
cnt_d = cnt_q;
cache_line_d = cache_line_q;
dirty_d = dirty_q;
shared_d = shared_q;
addr_offset_d = addr_offset_q;
id_d = id_q;
amo_d = amo_q;
size_d = size_q;
index = '0;
outstanding_aw_cnt_d = outstanding_aw_cnt_q;
case (state_q)
IDLE: begin
cnt_d = '0;
// we have an incoming request
if (req_i) begin
// is this a read or write?
// write
if (we_i) begin
// multiple outstanding write transactions are only
// allowed if they are guaranteed not to be reordered
// i.e. same ID
if (!any_outstanding_aw || ((id_i == id_q) && (amo_i == ariane_pkg::AMO_NONE))) begin
// the data is valid
axi_req_o.aw_valid = 1'b1;
axi_req_o.w_valid = 1'b1;
// store-conditional requires exclusive access
axi_req_o.aw.lock = amo_i == ariane_pkg::AMO_SC;
// its a single write
if (type_i == ariane_pkg::SINGLE_REQ) begin
// only a single write so the data is already the last one
axi_req_o.w.last = 1'b1;
// single req can be granted here
gnt_o = axi_resp_i.aw_ready & axi_resp_i.w_ready;
case ({
axi_resp_i.aw_ready, axi_resp_i.w_ready
})
2'b11: state_d = WAIT_B_VALID;
2'b01: state_d = WAIT_AW_READY;
2'b10: state_d = WAIT_LAST_W_READY;
default: state_d = IDLE;
endcase
if (axi_resp_i.aw_ready) begin
id_d = id_i;
amo_d = amo_i;
size_d = size_i;
end
// its a request for the whole cache line
end else begin
// bursts of AMOs unsupported
assert (amo_i == ariane_pkg::AMO_NONE)
else $fatal("Bursts of atomic operations are not supported");
axi_req_o.aw.len = BURST_SIZE[7:0]; // number of bursts to do
axi_req_o.w.data = wdata_i[0];
axi_req_o.w.strb = be_i[0];
if (axi_resp_i.w_ready) cnt_d = BURST_SIZE[ADDR_INDEX-1:0] - 1;
else cnt_d = BURST_SIZE[ADDR_INDEX-1:0];
case ({
axi_resp_i.aw_ready, axi_resp_i.w_ready
})
2'b11: state_d = WAIT_LAST_W_READY;
2'b01: state_d = WAIT_LAST_W_READY_AW_READY;
2'b10: state_d = WAIT_LAST_W_READY;
default: ;
endcase
end
end
// read
end else begin
// only multiple outstanding write transactions are allowed
if (!any_outstanding_aw) begin
axi_req_o.ar_valid = 1'b1;
// load-reserved requires exclusive access
axi_req_o.ar.lock = amo_i == ariane_pkg::AMO_LR;
gnt_o = axi_resp_i.ar_ready;
if (type_i != ariane_pkg::SINGLE_REQ) begin
assert (amo_i == ariane_pkg::AMO_NONE)
else $fatal("Bursts of atomic operations are not supported");
axi_req_o.ar.len = BURST_SIZE[7:0];
cnt_d = BURST_SIZE[ADDR_INDEX-1:0];
end
if (axi_resp_i.ar_ready) begin
state_d = (type_i == ariane_pkg::SINGLE_REQ) ? WAIT_R_VALID : WAIT_R_VALID_MULTIPLE;
addr_offset_d = addr_i[ADDR_INDEX-1+3:3];
end
end
end
end
end
// ~> from single write
WAIT_AW_READY: begin
axi_req_o.aw_valid = 1'b1;
if (axi_resp_i.aw_ready) begin
gnt_o = 1'b1;
state_d = WAIT_B_VALID;
id_d = id_i;
amo_d = amo_i;
size_d = size_i;
end
end
// ~> we need to wait for an aw_ready and there is at least one outstanding write
WAIT_LAST_W_READY_AW_READY: begin
axi_req_o.w_valid = 1'b1;
axi_req_o.w.last = (cnt_q == '0);
if (type_i == ariane_pkg::SINGLE_REQ) begin
axi_req_o.w.data = wdata_i[0];
axi_req_o.w.strb = be_i[0];
end else begin
axi_req_o.w.data = wdata_i[BURST_SIZE[ADDR_INDEX-1:0]-cnt_q];
axi_req_o.w.strb = be_i[BURST_SIZE[ADDR_INDEX-1:0]-cnt_q];
end
axi_req_o.aw_valid = 1'b1;
// we are here because we want to write a cache line
axi_req_o.aw.len = BURST_SIZE[7:0];
// we got an aw_ready
case ({
axi_resp_i.aw_ready, axi_resp_i.w_ready
})
// we got an aw ready
2'b01: begin
// are there any outstanding transactions?
if (cnt_q == 0) state_d = WAIT_AW_READY_BURST;
else // yes, so reduce the count and stay here
cnt_d = cnt_q - 1;
end
2'b10: state_d = WAIT_LAST_W_READY;
2'b11: begin
// we are finished
if (cnt_q == 0) begin
state_d = WAIT_B_VALID;
gnt_o = 1'b1;
// there are outstanding transactions
end else begin
state_d = WAIT_LAST_W_READY;
cnt_d = cnt_q - 1;
end
end
default: ;
endcase
end
// ~> all data has already been sent, we are only waiting for the aw_ready
WAIT_AW_READY_BURST: begin
axi_req_o.aw_valid = 1'b1;
axi_req_o.aw.len = BURST_SIZE[7:0];
if (axi_resp_i.aw_ready) begin
state_d = WAIT_B_VALID;
gnt_o = 1'b1;
end
end
// ~> from write, there is an outstanding write
WAIT_LAST_W_READY: begin
axi_req_o.w_valid = 1'b1;
if (type_i != ariane_pkg::SINGLE_REQ) begin
axi_req_o.w.data = wdata_i[BURST_SIZE[ADDR_INDEX-1:0]-cnt_q];
axi_req_o.w.strb = be_i[BURST_SIZE[ADDR_INDEX-1:0]-cnt_q];
end
// this is the last write
if (cnt_q == '0) begin
axi_req_o.w.last = 1'b1;
if (axi_resp_i.w_ready) begin
state_d = WAIT_B_VALID;
gnt_o = 1'b1;
end
end else if (axi_resp_i.w_ready) begin
cnt_d = cnt_q - 1;
end
end
// ~> finish write transaction
WAIT_B_VALID: begin
id_o = axi_resp_i.b.id;
// Write is valid
if (axi_resp_i.b_valid && !any_outstanding_aw) begin
axi_req_o.b_ready = 1'b1;
// some atomics must wait for read data
// we only accept it after accepting bvalid
if (amo_returns_data(amo_q)) begin
if (axi_resp_i.r_valid) begin
// return read data if valid
valid_o = 1'b1;
axi_req_o.r_ready = 1'b1;
state_d = IDLE;
rdata_o = axi_resp_i.r.data;
end else begin
// wait otherwise
state_d = WAIT_AMO_R_VALID;
end
end else begin
valid_o = 1'b1;
state_d = IDLE;
// store-conditional response
if (amo_q == ariane_pkg::AMO_SC) begin
if (axi_resp_i.b.resp == axi_pkg::RESP_EXOKAY) begin
// success -> return 0
rdata_o = 'b0;
end else begin
// failure -> when request is 64-bit, return 1;
// when request is 32-bit place a 1 in both upper
// and lower half words. The right word will be
// realigned/masked externally
rdata_o = size_q == 2'b10 ? (1'b1 << 32) | 64'b1 : 64'b1;
end
end
end
// if the request was not an atomic we can possibly issue
// other requests while waiting for the response
end else begin
if ((amo_q == ariane_pkg::AMO_NONE) && (outstanding_aw_cnt_q != MAX_OUTSTANDING_AW)) begin
state_d = IDLE;
outstanding_aw_cnt_d = outstanding_aw_cnt_q + 1;
end
end
end
// ~> some atomics wait for read data
WAIT_AMO_R_VALID: begin
// acknowledge data and terminate atomic
if (axi_resp_i.r_valid) begin
axi_req_o.r_ready = 1'b1;
state_d = IDLE;
valid_o = 1'b1;
rdata_o = axi_resp_i.r.data;
end
end
// ~> cacheline read, single read
WAIT_R_VALID_MULTIPLE, WAIT_R_VALID: begin
if (CRITICAL_WORD_FIRST) index = addr_offset_q + (BURST_SIZE[ADDR_INDEX-1:0] - cnt_q);
else index = BURST_SIZE[ADDR_INDEX-1:0] - cnt_q;
// reads are always wrapping here
axi_req_o.r_ready = 1'b1;
// this is the first read a.k.a the critical word
if (axi_resp_i.r_valid) begin
if (CRITICAL_WORD_FIRST) begin
// this is the first word of a cacheline read, e.g.: the word which was causing the miss
if (state_q == WAIT_R_VALID_MULTIPLE && cnt_q == BURST_SIZE) begin
critical_word_valid_o = 1'b1;
critical_word_o = axi_resp_i.r.data;
end
end else begin
// check if the address offset matches - then we are getting the critical word
if (index == addr_offset_q) begin
critical_word_valid_o = 1'b1;
critical_word_o = axi_resp_i.r.data;
end
end
// this is the last read
if (axi_resp_i.r.last) begin
id_d = axi_resp_i.r.id;
dirty_d = dirty;
shared_d = shared;
state_d = COMPLETE_READ;
end
// save the word
if (state_q == WAIT_R_VALID_MULTIPLE) begin
cache_line_d[index] = axi_resp_i.r.data;
end else cache_line_d[0] = axi_resp_i.r.data;
// Decrease the counter
cnt_d = cnt_q - 1;
end
end
// ~> read is complete
COMPLETE_READ: begin
valid_o = 1'b1;
state_d = IDLE;
id_o = id_q;
end
default: state_d = IDLE;
endcase
// This process handles B responses when accepting
// multiple outstanding write transactions
if (any_outstanding_aw && axi_resp_i.b_valid) begin
axi_req_o.b_ready = 1'b1;
valid_o = 1'b1;
// Right hand side contains non-registered signal as we want
// to preserve a possible increment from the WAIT_B_VALID state
outstanding_aw_cnt_d = outstanding_aw_cnt_d - 1;
end
end
generate
if (AXI_ACE) begin
// RACK / WACK
logic wack_d, wack_q;
logic rack_d, rack_q;
always_comb begin
// assert WACK the cycle after the BVALID/BREADY handshake is finished
wack_d = axi_req_o.b_ready & axi_resp_i.b_valid;
// assert RACK the cycle after the RVALID/RREADY handshake is finished
rack_d = axi_req_o.r_ready & axi_resp_i.r_valid;
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
wack_q <= 1'b0;
rack_q <= 1'b0;
end else begin
wack_q <= wack_d;
rack_q <= rack_d;
end
end
assign axi_req_o.wack = wack_q;
assign axi_req_o.rack = rack_q;
always_comb begin
// Default assignments
axi_req_o.aw.snoop = '0;
axi_req_o.aw.bar = '0;
axi_req_o.aw.domain = '0;
axi_req_o.aw.awunique = '0;
axi_req_o.ar.snoop = '0;
axi_req_o.ar.bar = '0;
axi_req_o.ar.domain = '0;
case (trans_type_i)
ace_pkg::READ_SHARED: begin
axi_req_o.ar.domain = 2'b01;
axi_req_o.ar.snoop = 4'b0001;
end
ace_pkg::READ_ONCE: begin
axi_req_o.ar.domain = 2'b01;
axi_req_o.ar.snoop = 4'b0000;
end
ace_pkg::READ_UNIQUE: begin
axi_req_o.ar.domain = 2'b01;
axi_req_o.ar.snoop = 4'b0111;
end
ace_pkg::READ_NO_SNOOP: begin
axi_req_o.ar.domain = 2'b00;
axi_req_o.ar.snoop = 4'b0000;
end
ace_pkg::CLEAN_UNIQUE: begin
axi_req_o.ar.domain = 2'b01;
axi_req_o.ar.snoop = 4'b1011;
end
ace_pkg::WRITE_UNIQUE: begin
axi_req_o.aw.domain = 2'b01;
axi_req_o.aw.snoop = 3'b000;
end
ace_pkg::WRITE_NO_SNOOP: begin
axi_req_o.aw.domain = 2'b00;
axi_req_o.aw.snoop = 3'b000;
end
ace_pkg::WRITE_BACK: begin
axi_req_o.aw.domain = 2'b00;
axi_req_o.aw.snoop = 3'b011;
end
endcase // case (trans_type_i)
end
end
endgenerate
// ----------------
// Registers
// ----------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
// start in flushing state and initialize the memory
state_q <= IDLE;
cnt_q <= '0;
cache_line_q <= '0;
addr_offset_q <= '0;
id_q <= '0;
amo_q <= ariane_pkg::AMO_NONE;
size_q <= '0;
dirty_q <= '0;
shared_q <= '0;
outstanding_aw_cnt_q <= '0;
end else begin
state_q <= state_d;
cnt_q <= cnt_d;
cache_line_q <= cache_line_d;
addr_offset_q <= addr_offset_d;
id_q <= id_d;
amo_q <= amo_d;
size_q <= size_d;
dirty_q <= dirty_d;
shared_q <= shared_d;
outstanding_aw_cnt_q <= outstanding_aw_cnt_d;
end
end
function automatic axi_pkg::atop_t atop_from_amo(ariane_pkg::amo_t amo);
axi_pkg::atop_t result = 6'b000000;
unique case (amo)
ariane_pkg::AMO_NONE: result = {axi_pkg::ATOP_NONE, 4'b0000};
ariane_pkg::AMO_SWAP: result = {axi_pkg::ATOP_ATOMICSWAP};
ariane_pkg::AMO_ADD:
result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_ADD};
ariane_pkg::AMO_AND:
result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_CLR};
ariane_pkg::AMO_OR:
result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SET};
ariane_pkg::AMO_XOR:
result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_EOR};
ariane_pkg::AMO_MAX:
result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SMAX};
ariane_pkg::AMO_MAXU:
result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_UMAX};
ariane_pkg::AMO_MIN:
result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_SMIN};
ariane_pkg::AMO_MINU:
result = {axi_pkg::ATOP_ATOMICLOAD, axi_pkg::ATOP_LITTLE_END, axi_pkg::ATOP_UMIN};
ariane_pkg::AMO_CAS1: result = {axi_pkg::ATOP_NONE, 4'b0000}; // Unsupported
ariane_pkg::AMO_CAS2: result = {axi_pkg::ATOP_NONE, 4'b0000}; // Unsupported
default: result = 6'b000000;
endcase
return result;
endfunction
function automatic logic amo_returns_data(ariane_pkg::amo_t amo);
axi_pkg::atop_t atop = atop_from_amo(amo);
logic is_load = atop[5:4] == axi_pkg::ATOP_ATOMICLOAD;
logic is_swap_or_cmp = atop[5:4] == axi_pkg::ATOP_ATOMICSWAP[5:4];
return is_load || is_swap_or_cmp;
endfunction
endmodule