diff --git a/icache.vhdl b/icache.vhdl index 89204a6..15ed7bd 100644 --- a/icache.vhdl +++ b/icache.vhdl @@ -176,8 +176,16 @@ architecture rtl of icache is signal itlb_valids : tlb_valids_t; signal itlb_tags : tlb_tags_t; signal itlb_ptes : tlb_ptes_t; - attribute ram_style of itlb_tags : signal is "distributed"; - attribute ram_style of itlb_ptes : signal is "distributed"; + + -- Values read from above arrays on a clock edge + signal itlb_valid : std_ulogic; + signal itlb_ttag : tlb_tag_t; + signal itlb_pte : tlb_pte_t; + + -- Values captured from a write to a TLB + signal itlb_bypass_valid : std_ulogic; + signal itlb_bypass_ra : std_ulogic_vector(REAL_ADDR_BITS - TLB_LG_PGSZ - 1 downto 0); + signal itlb_bypass_priv : std_ulogic; -- Privilege bit from PTE EAA field signal eaa_priv : std_ulogic; @@ -491,33 +499,61 @@ begin end process; end generate; + -- Read TLB using the NIA for the next cycle + itlb_read : process(clk) + variable tlb_req_index : std_ulogic_vector(TLB_BITS - 1 downto 0); + begin + if rising_edge(clk) then + if flush_in = '1' or i_in.req = '0' or (stall_in = '0' and stall_out = '0') then + tlb_req_index := hash_ea(i_in.next_nia); + if is_X(tlb_req_index) then + itlb_pte <= (others => 'X'); + itlb_ttag <= (others => 'X'); + itlb_valid <= 'X'; + else + itlb_pte <= itlb_ptes(to_integer(unsigned(tlb_req_index))); + itlb_ttag <= itlb_tags(to_integer(unsigned(tlb_req_index))); + itlb_valid <= itlb_valids(to_integer(unsigned(tlb_req_index))); + end if; + end if; + end if; + end process; + + -- Store TLB data being written for use in servicing the current request + itlb_bypass: process(clk) + begin + if rising_edge(clk) then + if rst = '1' then + itlb_bypass_valid <= '0'; + itlb_bypass_ra <= (others => '0'); + itlb_bypass_priv <= '0'; + elsif flush_in = '1' or i_in.req = '0' or stall_out = '0' then + itlb_bypass_valid <= '0'; + elsif m_in.tlbld = '1' then + assert i_in.nia(63 downto TLB_LG_PGSZ) = m_in.addr(63 downto TLB_LG_PGSZ); + itlb_bypass_valid <= '1'; + itlb_bypass_ra <= m_in.pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ); + itlb_bypass_priv <= m_in.pte(3); + end if; + end if; + end process; + -- TLB hit detection and real address generation itlb_lookup : process(all) - variable pte : tlb_pte_t; - variable ttag : tlb_tag_t; - variable tlb_req_index : std_ulogic_vector(TLB_BITS - 1 downto 0); begin - tlb_req_index := hash_ea(i_in.nia); - if is_X(tlb_req_index) then - pte := (others => 'X'); - ttag := (others => 'X'); - else - pte := itlb_ptes(to_integer(unsigned(tlb_req_index))); - ttag := itlb_tags(to_integer(unsigned(tlb_req_index))); - end if; - if i_in.virt_mode = '1' then - real_addr <= pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ) & + if itlb_bypass_valid = '1' then + real_addr <= itlb_bypass_ra & i_in.nia(TLB_LG_PGSZ - 1 downto 0); + ra_valid <= '1'; + eaa_priv <= itlb_bypass_priv; + elsif i_in.virt_mode = '1' then + real_addr <= itlb_pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ) & i_in.nia(TLB_LG_PGSZ - 1 downto 0); - if ttag = i_in.nia(63 downto TLB_LG_PGSZ + TLB_BITS) then - if is_X(tlb_req_index) then - ra_valid <= 'X'; - else - ra_valid <= itlb_valids(to_integer(unsigned(tlb_req_index))); - end if; + if itlb_ttag = i_in.nia(63 downto TLB_LG_PGSZ + TLB_BITS) then + ra_valid <= itlb_valid; else ra_valid <= '0'; end if; - eaa_priv <= pte(3); + eaa_priv <= itlb_pte(3); else real_addr <= addr_to_real(i_in.nia); ra_valid <= '1';