summaryrefslogtreecommitdiff
path: root/hdl/mem_cache.sv
blob: 181d8d76ee11e3fad211a8f39fb8b3192fb9005d (plain) (blame)
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
`include "defs.svh"

module mem_cache
    #(  SET_BITS    = 8
    )
    (   input   bit clock
    ,   input   bit reset

    ,   input   bit clear

    ,   output  bit             core_command_ready
    ,   input   bit             core_command_valid
    ,   input   core_to_mem_t   core_command_data

    ,   input   bit             ram_command_ready
    ,   output  bit             ram_command_valid
    ,   output  core_to_mem_t   ram_command_data

    ,   output  bit                 ram_response_ready
    ,   input   bit                 ram_response_valid
    ,   input   mem_to_core_t       ram_response_data

    ,   input   bit                 core_response_ready
    ,   output  bit                 core_response_valid
    ,   output  mem_to_core_t       core_response_data
    );

    localparam ADDRESS_TAG_LO   = $clog2(`RAM_LINE_WORDS)+SET_BITS;

    typedef bit [`PDP_ADDRESS_BITS-1:ADDRESS_TAG_LO]        address_tag_t;
    typedef bit [ADDRESS_TAG_LO-1:$clog2(`RAM_LINE_WORDS)]  set_t;

    typedef struct packed {
        bit             valid;
        address_tag_t   address;
    } tag_t;

    typedef struct packed {
        tag_t       tag;
        ram_line_t  data;
    } cache_entry_t;

    (* ramstyle = "no_rw_check, M9K" *) cache_entry_t   cache   [(1<<SET_BITS)-1:0];

    bit outstanding_fill;

    bit [SET_BITS:0]    reset_entry;

    always @(posedge clock) begin
        if (reset) begin
            core_command_ready = 0;
            ram_command_valid = 0;
            ram_response_ready = 0;
            core_response_valid = 0;
            outstanding_fill = 0;
            reset_entry = 0;
        end else begin
            if (clear)
                reset_entry = 0;

            if (ram_command_ready && ram_command_valid)
                ram_command_valid = 0;
            if (core_response_ready && core_response_valid)
                core_response_valid = 0;

            if (!outstanding_fill && !reset_entry[SET_BITS]) begin
                cache[reset_entry[SET_BITS-1:0]] = 0;
                ++reset_entry;
            end else if (ram_response_ready && ram_response_valid && outstanding_fill) begin
                automatic address_tag_t tag;
                automatic set_t set;
                automatic cache_entry_t entry;
                {tag, set} = ram_response_data.address;
                entry.tag.valid = 1;
                entry.tag.address = tag;
                entry.data = ram_response_data.data;
                cache[set] = entry;
                core_response_valid = 1;
                core_response_data = ram_response_data;
                outstanding_fill = 0;
            end else if (core_command_ready && core_command_valid) begin
                automatic address_tag_t tag;
                automatic set_t set;
                {tag, set} = core_command_data.address;
                if (core_command_data.write) begin
                    automatic cache_entry_t entry;
                    entry.tag.valid = 1;
                    entry.tag.address = tag;
                    // FIXME masked stores
                    entry.data = core_command_data.data;
                    cache[set] = entry;
                    ram_command_valid = 1;
                    ram_command_data = core_command_data;
                end else begin
                    automatic cache_entry_t entry = cache[set];
                    if (entry.tag.valid && entry.tag.address == tag) begin
                        core_response_valid = 1;
                        core_response_data.address = {tag, set};
                        core_response_data.data = entry.data;
                    end else begin
                        ram_command_valid = 1;
                        ram_command_data = core_command_data;
                        outstanding_fill = 1;
                    end
                end
            end

            core_command_ready = reset_entry[SET_BITS] && !ram_command_valid && !core_response_valid && !outstanding_fill;
            ram_response_ready = !core_response_valid;
        end
    end

endmodule