Add Tercel PHY reset synchronization
[microwatt.git] / icache.vhdl
index 3f1c15ff14f0c37078a39030a55b95f4c56a4c22..a658783c84ea32351e67a9c5c17cef91deec34a5 100644 (file)
@@ -98,7 +98,8 @@ architecture rtl of icache is
     -- SET_SIZE_BITS is the log base 2 of the set size
     constant SET_SIZE_BITS : natural := LINE_OFF_BITS + INDEX_BITS;
     -- TAG_BITS is the number of bits of the tag part of the address
-    constant TAG_BITS      : natural := REAL_ADDR_BITS - SET_SIZE_BITS;
+    -- the +1 is to allow the endianness to be stored in the tag
+    constant TAG_BITS      : natural := REAL_ADDR_BITS - SET_SIZE_BITS + 1;
     -- WAY_BITS is the number of bits to select a way
     constant WAY_BITS     : natural := log2(NUM_WAYS);
 
@@ -175,6 +176,7 @@ architecture rtl of icache is
        hit_nia   : std_ulogic_vector(63 downto 0);
        hit_smark : std_ulogic;
        hit_valid : std_ulogic;
+        big_endian: std_ulogic;
 
        -- Cache miss state (reload state machine)
         state            : state_t;
@@ -289,9 +291,10 @@ architecture rtl of icache is
     end;
 
     -- Get the tag value from the address
-    function get_tag(addr: std_ulogic_vector(REAL_ADDR_BITS - 1 downto 0)) return cache_tag_t is
+    function get_tag(addr: std_ulogic_vector(REAL_ADDR_BITS - 1 downto 0);
+                     endian: std_ulogic) return cache_tag_t is
     begin
-        return addr(REAL_ADDR_BITS - 1 downto SET_SIZE_BITS);
+        return endian & addr(REAL_ADDR_BITS - 1 downto SET_SIZE_BITS);
     end;
 
     -- Read a tag from a tag memory row
@@ -327,9 +330,9 @@ begin
        report "geometry bits don't add up" severity FAILURE;
     assert (LINE_OFF_BITS = ROW_OFF_BITS + ROW_LINEBITS)
        report "geometry bits don't add up" severity FAILURE;
-    assert (REAL_ADDR_BITS = TAG_BITS + INDEX_BITS + LINE_OFF_BITS)
+    assert (REAL_ADDR_BITS + 1 = TAG_BITS + INDEX_BITS + LINE_OFF_BITS)
        report "geometry bits don't add up" severity FAILURE;
-    assert (REAL_ADDR_BITS = TAG_BITS + ROW_BITS + ROW_OFF_BITS)
+    assert (REAL_ADDR_BITS + 1 = TAG_BITS + ROW_BITS + ROW_OFF_BITS)
        report "geometry bits don't add up" severity FAILURE;
 
     sim_debug: if SIM generate
@@ -359,6 +362,7 @@ begin
        signal wr_addr  : std_ulogic_vector(ROW_BITS-1 downto 0);
        signal dout     : cache_row_t;
        signal wr_sel   : std_ulogic_vector(ROW_SIZE-1 downto 0);
+        signal wr_dat   : std_ulogic_vector(wishbone_in.dat'left downto 0);
     begin
        way: entity work.cache_ram
            generic map (
@@ -372,10 +376,20 @@ begin
                rd_data => dout,
                wr_sel  => wr_sel,
                wr_addr => wr_addr,
-               wr_data => wishbone_in.dat
+               wr_data => wr_dat
                );
        process(all)
+            variable j: integer;
        begin
+            -- byte-swap read data if big endian
+            if r.store_tag(TAG_BITS - 1) = '0' then
+                wr_dat <= wishbone_in.dat;
+            else
+                for ii in 0 to (wishbone_in.dat'length / 8) - 1 loop
+                    j := ((ii / 4) * 4) + (3 - (ii mod 4));
+                    wr_dat(ii * 8 + 7 downto ii * 8) <= wishbone_in.dat(j * 8 + 7 downto j * 8);
+                end loop;
+            end if;
            do_read <= not (stall_in or use_previous);
            do_write <= '0';
            if wishbone_in.ack = '1' and replace_way = i then
@@ -384,8 +398,8 @@ begin
            cache_out(i) <= dout;
            rd_addr <= std_ulogic_vector(to_unsigned(req_row, ROW_BITS));
            wr_addr <= std_ulogic_vector(to_unsigned(r.store_row, ROW_BITS));
-            for i in 0 to ROW_SIZE-1 loop
-                wr_sel(i) <= do_write;
+            for ii in 0 to ROW_SIZE-1 loop
+                wr_sel(ii) <= do_write;
             end loop;
        end process;
     end generate;
@@ -486,7 +500,7 @@ begin
         -- last cycle, and we don't want the first 32-bit chunk, then we can
         -- keep the data we read last cycle and just use that.
         if unsigned(i_in.nia(INSN_BITS+2-1 downto 2)) /= 0 then
-            use_previous <= i_in.sequential and r.hit_valid;
+            use_previous <= i_in.req and i_in.sequential and r.hit_valid;
         else
             use_previous <= '0';
         end if;
@@ -494,7 +508,7 @@ begin
        -- Extract line, row and tag from request
         req_index <= get_index(i_in.nia);
         req_row <= get_row(i_in.nia);
-        req_tag <= get_tag(real_addr);
+        req_tag <= get_tag(real_addr, i_in.big_endian);
 
        -- Calculate address of beginning of cache row, will be
        -- used for cache miss processing if needed
@@ -550,6 +564,8 @@ begin
        i_out.nia <= r.hit_nia;
        i_out.stop_mark <= r.hit_smark;
         i_out.fetch_failed <= r.fetch_failed;
+        i_out.big_endian <= r.big_endian;
+        i_out.next_predicted <= i_in.predicted;
 
        -- Stall fetch1 if we have a miss on cache or TLB or a protection fault
        stall_out <= not (is_hit and access_ok);
@@ -590,6 +606,7 @@ begin
                 -- Send stop marks and NIA down regardless of validity
                 r.hit_smark <= i_in.stop_mark;
                 r.hit_nia <= i_in.nia;
+                r.big_endian <= i_in.big_endian;
             end if;
        end if;
     end process;