litedram: Defer clearing of tags & valids to improve timing
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 10 Jun 2020 08:00:12 +0000 (18:00 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 12 Jun 2020 11:01:34 +0000 (21:01 +1000)
Currently, there's a huge mux gathering the output of all the PLRUs
to select the victim way on cache miss. This is fed combinationally
into the clearing of the valid and tags.

In order to help timing, let's store it instead and perform the
clearing on the next cycle. The L2 doesn't respond to requests
when not in IDLE state so this should have no negative effects.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
litedram/extras/litedram-wrapper-l2.vhdl

index f2392f6b16238069bbe7ba37a939e3ea97cf7c0e..468ecfe4993c57807abe1d77e307b02cac0682d9 100644 (file)
@@ -235,6 +235,7 @@ architecture behaviour of litedram_wrapper is
 
      -- Cache state machine
     type state_t is (IDLE,             -- Normal load hit processing
+                     REFILL_CLR_TAG,   -- Cache refill clear tag
                      REFILL_WAIT_ACK); -- Cache refill wait ack
     signal state : state_t;
 
@@ -674,7 +675,7 @@ begin
             when others =>
                 wb_out.stall <= '0';
             end case;
-        when REFILL_WAIT_ACK =>
+        when others =>
             wb_out.stall <= '1';
         end case;
         
@@ -859,7 +860,6 @@ begin
     refill_machine : process(system_clk)
         variable tagset      : cache_tags_set_t;
         variable cmds_done   : boolean;
-        variable replace_way : way_t;
         variable wait_qdrain : boolean;
     begin
         if rising_edge(system_clk) then
@@ -887,23 +887,10 @@ begin
                     -- We need to read a cache line
                     if req_op = OP_LOAD_MISS and not wait_qdrain then
                         -- Grab way to replace
-                        replace_way := to_integer(unsigned(plru_victim(req_index)));
-
-                        -- Force misses on that way while refilling that line
-                        cache_valids(req_index)(replace_way) <= '0';
-
-                        -- Store new tag in selected way
-                        for i in 0 to NUM_WAYS-1 loop
-                            if i = replace_way then
-                                tagset := cache_tags(req_index);
-                                write_tag(i, tagset, req_tag);
-                                cache_tags(req_index) <= tagset;
-                            end if;
-                        end loop;
+                        refill_way <= to_integer(unsigned(plru_victim(req_index)));
 
                         -- Keep track of our index and way for subsequent stores
                         refill_index <= req_index;
-                        refill_way   <= replace_way;
                         refill_row   <= get_row(req_laddr);
 
                         -- Prep for first DRAM read
@@ -921,10 +908,27 @@ begin
                         end if;
 
                         -- Track that we had one request sent
+                        state <= REFILL_CLR_TAG;
+                    end if;
+
+                when REFILL_CLR_TAG | REFILL_WAIT_ACK =>
+
+                    -- Delayed tag clearing to help timing on PLRU output
+                    if state = REFILL_CLR_TAG then
+                        -- Force misses on that way while refilling that line
+                        cache_valids(req_index)(refill_way) <= '0';
+
+                        -- Store new tag in selected way
+                        for i in 0 to NUM_WAYS-1 loop
+                            if i = refill_way then
+                                tagset := cache_tags(req_index);
+                                write_tag(i, tagset, req_tag);
+                                cache_tags(req_index) <= tagset;
+                            end if;
+                        end loop;
                         state <= REFILL_WAIT_ACK;
                     end if;
 
-                when REFILL_WAIT_ACK =>
                     -- Commands are all sent if user_port0_cmd_valid is 0
                     cmds_done := refill_cmd_valid = '0';