mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-13 15:18:09 +00:00
icache: Read iTLB using early next NIA from fetch1
Using i_in.next_nia means that we can read the iTLB RAM arrays synchronously rather than asynchronously, which gives more opportunity for using block RAMs in FPGA implementations. The reading is gated by the stall signals because the next_nia can advance when stalled, but we need the iTLB entry for the instruction that i_in.nia points to. If we are stalled because of an iTLB miss, that means we don't see the new iTLB entry when it is written. Instead we save the new entry directly when it arrives and use it instead of the values read from the iTLB RAM. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
parent
f34a54d295
commit
723008b8c2
82
icache.vhdl
82
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;
|
||||
|
||||
-- TLB hit detection and real address generation
|
||||
itlb_lookup : process(all)
|
||||
variable pte : tlb_pte_t;
|
||||
variable ttag : tlb_tag_t;
|
||||
-- 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
|
||||
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 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)
|
||||
begin
|
||||
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';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user