File size: 3,418 Bytes
e4cdd5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
// ============================================================================
// Async FIFO
// ============================================================================
//
// Copyright 2026 Henry Arthur Shulayev Barnes / Catalyst Neuromorphic Ltd
// Company No. 17054540 — UK Patent Application No. 2602902.6
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the 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.
// ============================================================================
module async_fifo #(
    parameter DATA_WIDTH = 8,
    parameter ADDR_BITS  = 4
)(
    input  wire                  wr_clk,
    input  wire                  wr_rst_n,
    input  wire [DATA_WIDTH-1:0] wr_data,
    input  wire                  wr_en,
    output wire                  wr_full,

    input  wire                  rd_clk,
    input  wire                  rd_rst_n,
    input  wire                  rd_en,
    output wire [DATA_WIDTH-1:0] rd_data,
    output wire                  rd_empty
);

    localparam DEPTH = 1 << ADDR_BITS;

    reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];

    reg [ADDR_BITS:0] wr_bin, wr_gray;
    wire [ADDR_BITS:0] wr_bin_next  = wr_bin + 1;
    wire [ADDR_BITS:0] wr_gray_next = wr_bin_next ^ (wr_bin_next >> 1);

    reg [ADDR_BITS:0] rd_bin, rd_gray;
    wire [ADDR_BITS:0] rd_bin_next  = rd_bin + 1;
    wire [ADDR_BITS:0] rd_gray_next = rd_bin_next ^ (rd_bin_next >> 1);

    reg [ADDR_BITS:0] wr_gray_rd_s1, wr_gray_rd_s2;
    reg [ADDR_BITS:0] rd_gray_wr_s1, rd_gray_wr_s2;

    always @(posedge wr_clk or negedge wr_rst_n)
        if (!wr_rst_n) begin
            wr_bin  <= 0;
            wr_gray <= 0;
        end else if (wr_en && !wr_full) begin
            mem[wr_bin[ADDR_BITS-1:0]] <= wr_data;
            wr_bin  <= wr_bin_next;
            wr_gray <= wr_gray_next;
        end

    always @(posedge rd_clk or negedge rd_rst_n)
        if (!rd_rst_n) begin
            rd_bin  <= 0;
            rd_gray <= 0;
        end else if (rd_en && !rd_empty) begin
            rd_bin  <= rd_bin_next;
            rd_gray <= rd_gray_next;
        end

    always @(posedge rd_clk or negedge rd_rst_n)
        if (!rd_rst_n) begin
            wr_gray_rd_s1 <= 0;
            wr_gray_rd_s2 <= 0;
        end else begin
            wr_gray_rd_s1 <= wr_gray;
            wr_gray_rd_s2 <= wr_gray_rd_s1;
        end

    always @(posedge wr_clk or negedge wr_rst_n)
        if (!wr_rst_n) begin
            rd_gray_wr_s1 <= 0;
            rd_gray_wr_s2 <= 0;
        end else begin
            rd_gray_wr_s1 <= rd_gray;
            rd_gray_wr_s2 <= rd_gray_wr_s1;
        end

    assign wr_full  = (wr_gray == {~rd_gray_wr_s2[ADDR_BITS:ADDR_BITS-1],
                                     rd_gray_wr_s2[ADDR_BITS-2:0]});

    assign rd_empty = (rd_gray == wr_gray_rd_s2);

    assign rd_data  = mem[rd_bin[ADDR_BITS-1:0]];

endmodule