Source code: link.
Flit FIFO
In credit-based flow control network, a FIFO is needed to store multiple requests and responses and a credit counter is used to reflect the availability of buffer in a client. In FlitFIFO.sv
, we design a simple FIFO with valid-ready interface, based on chisel3 queue data structure (source).
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
module BasicFIFO #(parameter DEPTH = `FLIT_BUFFER_DEPTH, parameter DATA_WIDTH = `FLIT_WIDTH) (
input CLK,
input RST_N,
// Input
input [DATA_WIDTH - 1 : 0] enq_data,
input enq_valid,
output enq_ready,
// Output
output [DATA_WIDTH - 1 : 0] deq_data,
output deq_valid,
input deq_ready
);
logic [DATA_WIDTH - 1 : 0] buffer [0 : DEPTH];
logic [$clog2(DEPTH) - 1 : 0] enq_ptr;
logic [$clog2(DEPTH) - 1 : 0] deq_ptr;
logic ptr_match, empty, full, maybe_full;
logic enq_fire, deq_fire, do_enq, do_deq;
assign ptr_match = (enq_ptr == deq_ptr);
assign empty = ptr_match && !maybe_full;
assign full = ptr_match && maybe_full;
always_ff @(posedge CLK) begin
if (!RST_N) begin
enq_ptr <= 0;
deq_ptr <= 0;
maybe_full <= 0;
end else begin
if (do_enq)
enq_ptr <= enq_ptr + 1;
if (do_deq)
deq_ptr <= deq_ptr + 1;
if (do_enq != do_deq)
maybe_full <= do_enq;
end
end
always_ff @(posedge CLK) begin
if (!RST_N) begin
for (int i = 0; i < DEPTH; i++) begin
buffer[i] <= 0;
end
end else begin
if (do_enq)
buffer[enq_ptr] <= enq_data;
end
end
assign enq_fire = enq_valid && enq_ready;
assign deq_fire = deq_valid && deq_ready;
logic [DATA_WIDTH - 1 : 0] deq_data_;
logic deq_valid_;
assign deq_data = deq_data_;
assign deq_valid = deq_valid_;
always_comb begin
do_enq = enq_fire;
do_deq = deq_fire;
deq_data_ = buffer[deq_ptr];
deq_valid_ = !empty;
// Flow
if (empty) begin
if (deq_ready) begin
do_enq = 0;
end
do_deq = 0;
deq_data_ = enq_data;
end
if (enq_valid) begin
deq_valid_ = 1;
end
end
logic enq_ready_;
assign enq_ready = enq_ready_;
always_comb begin
enq_ready_ = !full;
// Pipe
if (deq_ready) begin
enq_ready_ = 1;
end
end
endmodule
A wrapper is also created to connect the network with the AXI interface and include the FIFO as follows.
1
2
3
4
5
6
7
+--------+ +------------+ +-------------+ +---------+
| Device | <--AXI4--> | AXI4Bridge | <--flits--> | InPortFIFO | <--flits-->| |
+--------+ +------------+ +-------------+ | |
^ | Network |
| +-------------+ | |
+-----------flits--> | OutPortFIFO | <--flits-->| |
+-------------+ +---------+
Test
See testbench_sample_axi4.sv
for test bench.
Results
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
# ---- Performing Reset ----
# 9: Port 0 send flit 1c2000000006d000000000002
# 9: [m0-aw] addr=00000002
# 10: Port 0 send flit 1c60000ffdeadbeefdeadbeef
# 10: Port 1 send flit 1e4000200006d000000000003
# 10: Port 0 get a credit
# 10: [m0- w] data=deadbeefdeadbeef
# 10: [m1-ar] addr=00000003
# 11: Port 0 send flit 1c60000ffdeadbeefdeadbef0
# 11: Port 0 get a credit
# 11: [m0- w] data=deadbeefdeadbef0
# 12: Port 0 send flit 1c60000ffdeadbeefdeadbef1
# 12: Port 2 recv flit 1c2000000006d000000000002
# 12: Port 0 get a credit
# 12: Port 1 get a credit
# 12: Port 2 put a credit
# 12: [m0- w] data=deadbeefdeadbef1
# 13: Port 0 send flit 1c60000ffdeadbeefdeadbef2
# 13: Port 0 get a credit
# 13: [m0- w] data=deadbeefdeadbef2
# 14: Port 0 send flit 1c60001ffdeadbeefdeadbef3
# 14: Port 2 recv flit 1c60000ffdeadbeefdeadbeef
# 14: Port 3 recv flit 1e4000200006d000000000003
# 14: Port 0 get a credit
# 14: Port 3 put a credit
# 14: [m0- w] data=deadbeefdeadbef3
# 14: [s0-aw] addr=00000002
# 15: Port 2 recv flit 1c60000ffdeadbeefdeadbef0
# 15: Port 0 get a credit
# 15: Port 2 put a credit
# 16: Port 2 recv flit 1c60000ffdeadbeefdeadbef1
# 16: [s0- w] data=deadbeefdeadbeef
# 16: [s1-ar] addr=00000003
# 17: Port 3 send flit 1ac000000deadbeefdeadbeef
# 17: Port 2 recv flit 1c60000ffdeadbeefdeadbef2
# 17: Port 2 put a credit
# 17: [s1- r] data=deadbeefdeadbeef
# 18: Port 3 send flit 1ac000000deadbeefdeadbef0
# 18: Port 2 recv flit 1c60001ffdeadbeefdeadbef3
# 18: Port 3 get a credit
# 18: [s0- w] data=deadbeefdeadbef0
# 18: [s1- r] data=deadbeefdeadbef0
# 19: Port 3 send flit 1ac000000deadbeefdeadbef1
# 19: Port 3 get a credit
# 19: Port 2 put a credit
# 19: [s1- r] data=deadbeefdeadbef1
# 20: Port 3 send flit 1ac000100deadbeefdeadbef2
# 20: Port 1 recv flit 1ac000000deadbeefdeadbeef
# 20: Port 3 get a credit
# 20: Port 1 put a credit
# 20: [s0- w] data=deadbeefdeadbef1
# 20: [s1- r] data=deadbeefdeadbef2
# 21: Port 1 recv flit 1ac000000deadbeefdeadbef0
# 21: Port 3 get a credit
# 21: Port 2 put a credit
# 21: [m1- r] data=deadbeefdeadbeef
# 22: Port 1 recv flit 1ac000000deadbeefdeadbef1
# 22: Port 1 put a credit
# 22: [s0- w] data=deadbeefdeadbef2
# 23: Port 1 recv flit 1ac000100deadbeefdeadbef2
# 23: Port 2 put a credit
# 23: [m1- r] data=deadbeefdeadbef0
# 24: Port 1 put a credit
# 24: [s0- w] data=deadbeefdeadbef3
# 25: Port 2 send flit 18a0000000000000000000000
# 25: [m1- r] data=deadbeefdeadbef1
# 25: [s0- b]
# 26: Port 2 get a credit
# 26: Port 1 put a credit
# 27: [m1- r] data=deadbeefdeadbef2
# 28: Port 0 recv flit 18a0000000000000000000000
# 28: Port 0 put a credit
# 29: [m0- b]
# actual:deadbeefdeadbeef expected:deadbeefdeadbeef
#
# actual:deadbeefdeadbef0 expected:deadbeefdeadbef0
#
# actual:deadbeefdeadbef1 expected:deadbeefdeadbef1
#
# actual:deadbeefdeadbef2 expected:deadbeefdeadbef2
#
# Pass
# actual:deadbeefdeadbeef expected:deadbeefdeadbeef
#
# actual:deadbeefdeadbef0 expected:deadbeefdeadbef0
#
# actual:deadbeefdeadbef1 expected:deadbeefdeadbef1
#
# actual:deadbeefdeadbef2 expected:deadbeefdeadbef2
#
# Pass