Rodrigo Huerta | 46bbb38 | 2021-10-29 19:59:13 +0200 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * This file is part of the Elpis processor project. |
| 4 | * |
| 5 | * Copyright © 2020-present. All rights reserved. |
| 6 | * Authors: Aurora Tomas and Rodrigo Huerta. |
| 7 | * |
| 8 | * This file is licensed under both the BSD-3 license for individual/non-commercial |
| 9 | * use. Full text of both licenses can be found in LICENSE file. |
| 10 | */ |
| 11 | |
| 12 | `default_nettype none |
| 13 | |
| 14 | `ifdef TESTS |
| 15 | `include "elpis/definitions.v" |
| 16 | `else |
| 17 | `include "/project/openlane/user_proj_example/../../verilog/rtl/elpis/definitions.v" |
| 18 | `endif |
| 19 | |
| 20 | module storebuffer( |
| 21 | input clk, |
| 22 | input reset, |
| 23 | input[31:0] addr_in, |
| 24 | input[31:0] data_in, |
| 25 | input is_byte, |
| 26 | input sb_we, // Add a new entry into SB |
| 27 | input sb_re, // Read request (bypass) from an entry of SB |
| 28 | input stall_dcache, |
| 29 | input hit_dtlb, |
| 30 | output reg sb_hit, |
| 31 | output full_out, |
| 32 | output empty_out, |
| 33 | output reg[31:0] addr_out, |
| 34 | output reg[31:0] data_out, |
| 35 | output reg is_byte_out, |
| 36 | output reg drain_out, |
| 37 | output reg is_data_to_cache |
| 38 | ); |
| 39 | reg useless_bit, hold_value_to_cache; |
| 40 | reg[31:0] sb_addr[0:`SB_NUM_ENTRIES-1]; |
| 41 | reg[31:0] sb_data[0:`SB_NUM_ENTRIES-1]; |
| 42 | reg sb_size[0:`SB_NUM_ENTRIES-1]; // 0 - word, 1 - byte |
| 43 | reg sb_valid[0:`SB_NUM_ENTRIES-1]; |
| 44 | |
| 45 | reg[$clog2(`SB_NUM_ENTRIES)-1:0] head; |
| 46 | reg[$clog2(`SB_NUM_ENTRIES)-1:0] tail; |
| 47 | reg[$clog2(`SB_NUM_ENTRIES)-1:0] tail_last; |
| 48 | reg[$clog2(`SB_NUM_ENTRIES):0] entry_count; |
| 49 | |
| 50 | wire[31:0] ld_first_byte, ld_last_byte; |
| 51 | wire[1:0] offset; |
| 52 | |
| 53 | assign ld_first_byte = addr_in; |
| 54 | assign ld_last_byte = (is_byte) ? addr_in : (addr_in+3); |
| 55 | assign offset = addr_in[1:0]; |
| 56 | |
| 57 | assign empty_out = (entry_count == 0); |
| 58 | assign full_out = (entry_count == `SB_NUM_ENTRIES); |
| 59 | |
| 60 | reg[1:0] hit_pos; |
| 61 | integer i; |
| 62 | always@(*) begin |
| 63 | sb_hit = 1'b0; |
Rodrigo Huerta | ad8a743 | 2021-11-02 21:34:04 +0100 | [diff] [blame] | 64 | hit_pos = 2'b0; |
Rodrigo Huerta | 46bbb38 | 2021-10-29 19:59:13 +0200 | [diff] [blame] | 65 | for (i = 0; (i < `SB_NUM_ENTRIES); i=i+1) begin |
| 66 | if (sb_valid[i] && (sb_addr[i] <= ld_first_byte) && ( (sb_addr[i] + (sb_size[i] ? 0 : 3'b11) ) >= ld_last_byte) ) begin |
| 67 | sb_hit = 1'b1; |
| 68 | hit_pos = i[1:0]; |
| 69 | end |
| 70 | end |
Rodrigo Huerta | 46bbb38 | 2021-10-29 19:59:13 +0200 | [diff] [blame] | 71 | end |
| 72 | |
| 73 | always@(posedge clk) begin |
| 74 | if (reset) begin |
| 75 | head <= 2'b0; |
| 76 | tail <= 2'b0; |
| 77 | entry_count <= 3'b0; |
| 78 | for(i = 0; i < `SB_NUM_ENTRIES; i=i+1) begin |
| 79 | sb_valid[i] <= 1'b0; |
| 80 | end |
| 81 | end else begin |
| 82 | if (sb_re && sb_hit) begin |
| 83 | data_out <= (is_byte && sb_size[hit_pos]) ? {24'b0, sb_data[hit_pos][offset*'d8]} : sb_data[hit_pos]; |
| 84 | end |
| 85 | |
| 86 | if(sb_we && sb_hit) begin |
| 87 | if (is_byte && !sb_size[hit_pos]) begin |
| 88 | // We have a word and want to write a byte |
| 89 | sb_data[hit_pos][offset*8+:8] <= data_in[7:0]; |
| 90 | end else if (is_byte && sb_size[hit_pos]) begin |
| 91 | // We have a byte and want to write a byte |
| 92 | sb_data[hit_pos] <= {24'b0, data_in[7:0]}; |
| 93 | end else begin |
| 94 | // We have (byte or word) and we want to write a word |
| 95 | sb_data[hit_pos] <= data_in; |
| 96 | sb_size[hit_pos] <= 1'b0; |
| 97 | end |
| 98 | end |
| 99 | |
| 100 | if ((full_out && !stall_dcache) || (!sb_we && !sb_re && !empty_out && !stall_dcache)) begin |
| 101 | drain_out <= 1'b1; |
| 102 | tail_last <= tail; |
| 103 | is_data_to_cache <= 1'b1; |
| 104 | addr_out <= sb_addr[tail]; |
| 105 | data_out <= sb_data[tail]; |
| 106 | is_byte_out <= sb_size[tail]; |
| 107 | entry_count <= entry_count - 1'b1; |
| 108 | sb_valid[tail] <= 1'b0; |
| 109 | {useless_bit, tail} <= (tail+1'b1)%`SB_NUM_ENTRIES; |
| 110 | hold_value_to_cache <= 1'b1; |
| 111 | end else if(stall_dcache && hold_value_to_cache) begin |
| 112 | drain_out <= 1'b1; |
| 113 | is_data_to_cache <= 1'b1; |
| 114 | addr_out <= sb_addr[tail_last]; |
| 115 | data_out <= sb_data[tail_last]; |
| 116 | is_byte_out <= sb_size[tail_last]; |
| 117 | hold_value_to_cache <= 1'b1; |
| 118 | end else begin |
| 119 | drain_out <= 1'b0; |
| 120 | is_data_to_cache <= 1'b0; |
| 121 | hold_value_to_cache <= 1'b0; |
| 122 | tail_last <= 'b0; |
| 123 | end |
| 124 | |
| 125 | if (sb_we && !full_out && !sb_hit && hit_dtlb) begin |
| 126 | sb_addr[head] <= addr_in; |
| 127 | sb_data[head] <= data_in; |
| 128 | sb_size[head] <= is_byte; |
| 129 | sb_valid[head] <= 1'b1; |
| 130 | entry_count <= entry_count + 1'b1; |
| 131 | {useless_bit, head} <= (head + 1'b1)%`SB_NUM_ENTRIES; |
| 132 | end |
| 133 | end |
| 134 | end |
| 135 | |
| 136 | endmodule |