forked from aignacio/axi_dma
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dma_fifo.sv
100 lines (91 loc) · 3.05 KB
/
dma_fifo.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
/**
* File : dma_fifo.sv
* License : MIT license <Check LICENSE>
* Author : Anderson Ignacio da Silva (aignacio) <[email protected]>
* Date : 10.06.2022
* Last Modified Date: 19.06.2022
*/
module dma_fifo
import amba_axi_pkg::*;
import dma_utils_pkg::*;
#(
parameter int SLOTS = `DMA_FIFO_DEPTH,
parameter int WIDTH = `DMA_DATA_WIDTH
)(
input clk,
input rst,
input clear_i,
input write_i,
input read_i,
input [WIDTH-1:0] data_i,
output logic [WIDTH-1:0] data_o,
output logic error_o,
output logic full_o,
output logic empty_o,
output logic [$clog2(SLOTS>1?SLOTS:2):0] ocup_o,
output logic [$clog2(SLOTS>1?SLOTS:2):0] free_o
);
`define MSB_SLOT $clog2(SLOTS>1?SLOTS:2)
typedef logic [$clog2(SLOTS>1?SLOTS:2):0] msb_t;
logic [SLOTS-1:0] [WIDTH-1:0] fifo_ff;
msb_t write_ptr_ff;
msb_t read_ptr_ff;
msb_t next_write_ptr;
msb_t next_read_ptr;
msb_t fifo_ocup;
always_comb begin
next_read_ptr = read_ptr_ff;
next_write_ptr = write_ptr_ff;
if (SLOTS == 1) begin
empty_o = (write_ptr_ff == read_ptr_ff);
full_o = (write_ptr_ff[0] != read_ptr_ff[0]);
data_o = empty_o ? '0 : fifo_ff[0];
end
else begin
empty_o = (write_ptr_ff == read_ptr_ff);
full_o = (write_ptr_ff[`MSB_SLOT-1:0] == read_ptr_ff[`MSB_SLOT-1:0]) &&
(write_ptr_ff[`MSB_SLOT] != read_ptr_ff[`MSB_SLOT]);
data_o = empty_o ? '0 : fifo_ff[read_ptr_ff[`MSB_SLOT-1:0]];
end
if (write_i && ~full_o)
next_write_ptr = write_ptr_ff + 'd1;
if (read_i && ~empty_o)
next_read_ptr = read_ptr_ff + 'd1;
error_o = (write_i && full_o) || (read_i && empty_o);
fifo_ocup = write_ptr_ff - read_ptr_ff;
free_o = msb_t'(SLOTS) - fifo_ocup;
ocup_o = fifo_ocup;
end
always_ff @ (posedge clk) begin
if (rst) begin
write_ptr_ff <= '0;
read_ptr_ff <= '0;
end
else begin
if (clear_i) begin
write_ptr_ff <= '0;
read_ptr_ff <= '0;
end
else begin
write_ptr_ff <= next_write_ptr;
read_ptr_ff <= next_read_ptr;
if (write_i && ~full_o) begin
if (SLOTS == 1) begin
fifo_ff[0] <= data_i;
end
else begin
fifo_ff[write_ptr_ff[`MSB_SLOT-1:0]] <= data_i;
end
end
end
end
end
`ifndef NO_ASSERTIONS
initial begin
illegal_fifo_slot : assert (2**$clog2(SLOTS) == SLOTS)
else $error("FIFO Slots must be power of 2");
min_fifo_size : assert (SLOTS >= 1)
else $error("FIFO size of SLOTS defined is illegal!");
end
`endif
endmodule