diff options
Diffstat (limited to '')
| -rw-r--r-- | hdl/mem_cache.sv | 189 |
1 files changed, 143 insertions, 46 deletions
diff --git a/hdl/mem_cache.sv b/hdl/mem_cache.sv index 181d8d7..e7fcac7 100644 --- a/hdl/mem_cache.sv +++ b/hdl/mem_cache.sv | |||
| @@ -6,8 +6,6 @@ module mem_cache | |||
| 6 | ( input bit clock | 6 | ( input bit clock |
| 7 | , input bit reset | 7 | , input bit reset |
| 8 | 8 | ||
| 9 | , input bit clear | ||
| 10 | |||
| 11 | , output bit core_command_ready | 9 | , output bit core_command_ready |
| 12 | , input bit core_command_valid | 10 | , input bit core_command_valid |
| 13 | , input core_to_mem_t core_command_data | 11 | , input core_to_mem_t core_command_data |
| @@ -32,6 +30,7 @@ module mem_cache | |||
| 32 | 30 | ||
| 33 | typedef struct packed { | 31 | typedef struct packed { |
| 34 | bit valid; | 32 | bit valid; |
| 33 | bit dirty; | ||
| 35 | address_tag_t address; | 34 | address_tag_t address; |
| 36 | } tag_t; | 35 | } tag_t; |
| 37 | 36 | ||
| @@ -40,73 +39,171 @@ module mem_cache | |||
| 40 | ram_line_t data; | 39 | ram_line_t data; |
| 41 | } cache_entry_t; | 40 | } cache_entry_t; |
| 42 | 41 | ||
| 43 | (* ramstyle = "no_rw_check, M9K" *) cache_entry_t cache [(1<<SET_BITS)-1:0]; | 42 | struct packed { |
| 43 | set_t address; | ||
| 44 | bit read_enable; | ||
| 45 | bit write_enable; | ||
| 46 | cache_entry_t read_data; | ||
| 47 | cache_entry_t write_data; | ||
| 48 | } cache[1:0]; | ||
| 44 | 49 | ||
| 45 | bit outstanding_fill; | 50 | altsyncram |
| 51 | #( .address_reg_b("CLOCK0") | ||
| 52 | , .clock_enable_input_a("BYPASS"), .clock_enable_input_b("BYPASS") | ||
| 53 | , .clock_enable_output_a("BYPASS"), .clock_enable_output_b("BYPASS") | ||
| 54 | , .indata_reg_b("CLOCK0") | ||
| 55 | , .numwords_a(1 << SET_BITS), .numwords_b(1 << SET_BITS) | ||
| 56 | , .operation_mode("BIDIR_DUAL_PORT") | ||
| 57 | , .outdata_aclr_a("NONE"), .outdata_aclr_b("NONE") | ||
| 58 | , .outdata_reg_a("UNREGISTERED"), .outdata_reg_b("UNREGISTERED") | ||
| 59 | , .power_up_uninitialized("TRUE") | ||
| 60 | , .ram_block_type("M9K") | ||
| 61 | , .read_during_write_mode_mixed_ports("OLD_DATA") | ||
| 62 | , .read_during_write_mode_port_a("OLD_DATA"), .read_during_write_mode_port_b("OLD_DATA") | ||
| 63 | , .widthad_a(SET_BITS), .widthad_b(SET_BITS) | ||
| 64 | , .width_a($bits(cache_entry_t)), .width_b($bits(cache_entry_t)) | ||
| 65 | , .width_byteena_a(1), .width_byteena_b(1) | ||
| 66 | , .wrcontrol_wraddress_reg_b("CLOCK0") | ||
| 67 | ) cache_controller | ||
| 68 | ( .address_a(cache[0].address), .address_b(cache[1].address) | ||
| 69 | , .clock0(~clock) | ||
| 70 | , .data_a(cache[0].write_data), .data_b(cache[1].write_data) | ||
| 71 | , .rden_a(cache[0].read_enable), .rden_b(cache[1].read_enable) | ||
| 72 | , .wren_a(cache[0].write_enable), .wren_b(cache[1].write_enable) | ||
| 73 | , .q_a(cache[0].read_data), .q_b(cache[1].read_data) | ||
| 74 | , .aclr0(1'b0), .aclr1(1'b0) | ||
| 75 | , .addressstall_a(1'b0), .addressstall_b(1'b0) | ||
| 76 | , .byteena_a(1'b1), .byteena_b(1'b1) | ||
| 77 | , .clock1(1'b1) | ||
| 78 | , .clocken0(1'b1), .clocken1(1'b1), .clocken2(1'b1), .clocken3(1'b1) | ||
| 79 | , .eccstatus() | ||
| 80 | ); | ||
| 46 | 81 | ||
| 47 | bit [SET_BITS:0] reset_entry; | 82 | bit [SET_BITS:0] reset_entry; |
| 48 | 83 | ||
| 84 | // "The" fill buffer | ||
| 85 | address_tag_t working_tag; | ||
| 86 | set_t working_set; | ||
| 87 | |||
| 88 | (* syn_encoding = "one-hot" *) enum int unsigned | ||
| 89 | { AWAIT_CORE_COMMAND | ||
| 90 | , AWAIT_CACHE | ||
| 91 | , SEND_FILL_REQUEST | ||
| 92 | , AWAIT_RAM_RESPONSE | ||
| 93 | } state; | ||
| 94 | |||
| 49 | always @(posedge clock) begin | 95 | always @(posedge clock) begin |
| 50 | if (reset) begin | 96 | if (reset) begin |
| 51 | core_command_ready = 0; | 97 | core_command_ready = 0; |
| 52 | ram_command_valid = 0; | 98 | ram_command_valid = 0; |
| 53 | ram_response_ready = 0; | 99 | ram_response_ready = 0; |
| 54 | core_response_valid = 0; | 100 | core_response_valid = 0; |
| 55 | outstanding_fill = 0; | ||
| 56 | reset_entry = 0; | 101 | reset_entry = 0; |
| 102 | cache[0].address = 0; cache[1].address = 0; | ||
| 103 | cache[0].read_enable = 0; cache[1].read_enable = 0; | ||
| 104 | cache[0].write_enable = 0; cache[1].write_enable = 0; | ||
| 105 | cache[0].write_data = 0; cache[1].write_data = 0; | ||
| 106 | state = state.first; | ||
| 57 | end else begin | 107 | end else begin |
| 58 | if (clear) | ||
| 59 | reset_entry = 0; | ||
| 60 | |||
| 61 | if (ram_command_ready && ram_command_valid) | 108 | if (ram_command_ready && ram_command_valid) |
| 62 | ram_command_valid = 0; | 109 | ram_command_valid = 0; |
| 63 | if (core_response_ready && core_response_valid) | 110 | if (core_response_ready && core_response_valid) |
| 64 | core_response_valid = 0; | 111 | core_response_valid = 0; |
| 65 | 112 | ||
| 66 | if (!outstanding_fill && !reset_entry[SET_BITS]) begin | 113 | if (!reset_entry[SET_BITS]) begin |
| 67 | cache[reset_entry[SET_BITS-1:0]] = 0; | 114 | cache[0].address = reset_entry[SET_BITS-1:0]; |
| 68 | ++reset_entry; | 115 | cache[1].address = reset_entry[SET_BITS-1:0] + 1; |
| 69 | end else if (ram_response_ready && ram_response_valid && outstanding_fill) begin | 116 | cache[0].read_enable = 0; cache[1].read_enable = 0; |
| 70 | automatic address_tag_t tag; | 117 | cache[0].write_enable = 1; cache[1].write_enable = 1; |
| 71 | automatic set_t set; | 118 | cache[0].write_data = 0; cache[1].write_data = 0; |
| 72 | automatic cache_entry_t entry; | 119 | reset_entry += 2; |
| 73 | {tag, set} = ram_response_data.address; | 120 | end else begin |
| 74 | entry.tag.valid = 1; | 121 | case (state) |
| 75 | entry.tag.address = tag; | 122 | |
| 76 | entry.data = ram_response_data.data; | 123 | AWAIT_CORE_COMMAND: begin |
| 77 | cache[set] = entry; | 124 | cache[0].read_enable = 0; |
| 78 | core_response_valid = 1; | 125 | cache[0].write_enable = 0; |
| 79 | core_response_data = ram_response_data; | 126 | |
| 80 | outstanding_fill = 0; | 127 | if (core_command_ready && core_command_valid) begin |
| 81 | end else if (core_command_ready && core_command_valid) begin | 128 | {working_tag, working_set} = core_command_data.address; |
| 82 | automatic address_tag_t tag; | 129 | cache[0].address = working_set; |
| 83 | automatic set_t set; | 130 | cache[0].read_enable = 1; |
| 84 | {tag, set} = core_command_data.address; | 131 | cache[0].write_enable = core_command_data.write; |
| 85 | if (core_command_data.write) begin | 132 | cache[0].write_data.tag.valid = 1; |
| 86 | automatic cache_entry_t entry; | 133 | cache[0].write_data.tag.dirty = 1; |
| 87 | entry.tag.valid = 1; | 134 | cache[0].write_data.tag.address = working_tag; |
| 88 | entry.tag.address = tag; | 135 | cache[0].write_data.data = core_command_data.data; |
| 89 | // FIXME masked stores | 136 | state = AWAIT_CACHE; |
| 90 | entry.data = core_command_data.data; | 137 | end |
| 91 | cache[set] = entry; | 138 | end |
| 92 | ram_command_valid = 1; | 139 | |
| 93 | ram_command_data = core_command_data; | 140 | AWAIT_CACHE: begin |
| 94 | end else begin | 141 | if (cache[0].read_data.tag.valid && cache[0].read_data.tag.dirty && cache[0].read_data.tag.address != working_tag) begin |
| 95 | automatic cache_entry_t entry = cache[set]; | 142 | ram_command_valid = 1; |
| 96 | if (entry.tag.valid && entry.tag.address == tag) begin | 143 | ram_command_data.address = {cache[0].read_data.tag.address, working_set}; |
| 144 | ram_command_data.write = 1; | ||
| 145 | ram_command_data.snoop_response = 0; | ||
| 146 | ram_command_data.data = cache[0].read_data.data; | ||
| 147 | ram_command_data.mask = ~0; | ||
| 148 | state = cache[0].write_enable ? AWAIT_CORE_COMMAND : SEND_FILL_REQUEST; | ||
| 149 | end else if (cache[0].write_enable) begin | ||
| 150 | core_command_ready = !core_response_valid && !ram_command_valid; | ||
| 151 | state = AWAIT_CORE_COMMAND; | ||
| 152 | end else if (cache[0].read_data.tag.valid && cache[0].read_data.tag.address == working_tag) begin | ||
| 97 | core_response_valid = 1; | 153 | core_response_valid = 1; |
| 98 | core_response_data.address = {tag, set}; | 154 | core_response_data.address = {working_tag, working_set}; |
| 99 | core_response_data.data = entry.data; | 155 | core_response_data.snoop = 0; |
| 156 | core_response_data.data_valid = 1; | ||
| 157 | core_response_data.data = cache[0].read_data.data; | ||
| 158 | state = AWAIT_CORE_COMMAND; | ||
| 100 | end else begin | 159 | end else begin |
| 101 | ram_command_valid = 1; | 160 | ram_command_valid = 1; |
| 102 | ram_command_data = core_command_data; | 161 | ram_command_data.address = {working_tag, working_set}; |
| 103 | outstanding_fill = 1; | 162 | ram_command_data.write = 0; |
| 163 | ram_command_data.snoop_response = 0; | ||
| 164 | state = AWAIT_RAM_RESPONSE; | ||
| 104 | end | 165 | end |
| 166 | |||
| 167 | cache[0].read_enable = 0; | ||
| 168 | cache[0].write_enable = 0; | ||
| 105 | end | 169 | end |
| 106 | end | ||
| 107 | 170 | ||
| 108 | core_command_ready = reset_entry[SET_BITS] && !ram_command_valid && !core_response_valid && !outstanding_fill; | 171 | SEND_FILL_REQUEST: begin |
| 109 | ram_response_ready = !core_response_valid; | 172 | cache[0].read_enable = 0; |
| 173 | cache[0].write_enable = 0; | ||
| 174 | |||
| 175 | if (!ram_command_valid) begin | ||
| 176 | ram_command_valid = 1; | ||
| 177 | ram_command_data.address = {working_tag, working_set}; | ||
| 178 | ram_command_data.write = 0; | ||
| 179 | ram_command_data.snoop_response = 0; | ||
| 180 | state = AWAIT_RAM_RESPONSE; | ||
| 181 | end | ||
| 182 | end | ||
| 183 | |||
| 184 | AWAIT_RAM_RESPONSE: begin | ||
| 185 | cache[0].read_enable = 0; | ||
| 186 | cache[0].write_enable = 0; | ||
| 187 | |||
| 188 | if (ram_response_valid && ram_response_data.address == {working_tag, working_set} && ram_response_data.data_valid) begin | ||
| 189 | core_response_valid = 1; | ||
| 190 | core_response_data = ram_response_data; | ||
| 191 | cache[0].address = working_set; | ||
| 192 | cache[0].read_enable = 0; | ||
| 193 | cache[0].write_enable = 1; | ||
| 194 | cache[0].write_data.tag.valid = 1; | ||
| 195 | cache[0].write_data.tag.dirty = 0; | ||
| 196 | cache[0].write_data.tag.address = working_tag; | ||
| 197 | cache[0].write_data.data = ram_response_data.data; | ||
| 198 | state = AWAIT_CORE_COMMAND; | ||
| 199 | end | ||
| 200 | end | ||
| 201 | |||
| 202 | endcase | ||
| 203 | |||
| 204 | core_command_ready = state == AWAIT_CORE_COMMAND && !core_response_valid && !ram_command_valid; | ||
| 205 | ram_response_ready = state == AWAIT_RAM_RESPONSE && !core_response_valid && !ram_command_valid; | ||
| 206 | end | ||
| 110 | end | 207 | end |
| 111 | end | 208 | end |
| 112 | 209 | ||
