@ -80,6 +80,9 @@ architecture behave of loadstore1 is
dsisr : std_ulogic_vector(31 downto 0);
dsisr : std_ulogic_vector(31 downto 0);
instr_fault : std_ulogic;
instr_fault : std_ulogic;
sprval : std_ulogic_vector(63 downto 0);
sprval : std_ulogic_vector(63 downto 0);
busy : std_ulogic;
wait_dcache : std_ulogic;
wait_mmu : std_ulogic;
end record;
end record;
type byte_sel_t is array(0 to 7) of std_ulogic;
type byte_sel_t is array(0 to 7) of std_ulogic;
@ -128,6 +131,9 @@ begin
if rising_edge(clk) then
if rising_edge(clk) then
if rst = '1' then
if rst = '1' then
r.state <= IDLE;
r.state <= IDLE;
r.busy <= '0';
r.wait_dcache <= '0';
r.wait_mmu <= '0';
else
else
r <= rin;
r <= rin;
end if;
end if;
@ -228,8 +234,17 @@ begin
-- compute (addr + 8) & ~7 for the second doubleword when unaligned
-- compute (addr + 8) & ~7 for the second doubleword when unaligned
next_addr := std_ulogic_vector(unsigned(r.addr(63 downto 3)) + 1) & "000";
next_addr := std_ulogic_vector(unsigned(r.addr(63 downto 3)) + 1) & "000";
-- Busy calculation.
-- We need to minimize the delay from clock to busy valid because it
-- gates the start of execution of the next instruction.
busy := r.busy or (r.wait_dcache and not d_in.valid) or (r.wait_mmu and not m_in.done);
done := '0';
done := '0';
if r.state /= IDLE and busy = '0' then
done := '1';
end if;
exception := '0';
exception := '0';
case r.state is
case r.state is
when IDLE =>
when IDLE =>
@ -255,7 +270,6 @@ begin
dsisr(63 - 38) := not r.load;
dsisr(63 - 38) := not r.load;
-- XXX there is no architected bit for this
-- XXX there is no architected bit for this
dsisr(63 - 35) := d_in.cache_paradox;
dsisr(63 - 35) := d_in.cache_paradox;
v.state := IDLE;
else
else
-- Look up the translation for TLB miss
-- Look up the translation for TLB miss
-- and also for permission error and RC error
-- and also for permission error and RC error
@ -279,8 +293,6 @@ begin
else
else
-- stores write back rA update in this cycle
-- stores write back rA update in this cycle
do_update := r.update;
do_update := r.update;
done := '1';
v.state := IDLE;
end if;
end if;
end if;
end if;
end if;
end if;
@ -294,53 +306,36 @@ begin
byte_sel := r.first_bytes;
byte_sel := r.first_bytes;
end if;
end if;
if m_in.done = '1' then
if m_in.done = '1' then
if m_in.invalid = '0' and m_in.perm_error = '0' and m_in.rc_error = '0' and
if r.instr_fault = '0' then
m_in.badtree = '0' and m_in.segerr = '0' then
-- retry the request now that the MMU has installed a TLB entry
if r.instr_fault = '0' then
req := '1';
-- retry the request now that the MMU has installed a TLB entry
if r.last_dword = '0' then
req := '1';
v.state := SECOND_REQ;
if r.last_dword = '0' then
v.state := SECOND_REQ;
else
v.state := ACK_WAIT;
end if;
else
else
-- nothing to do, the icache retries automatically
v.state := ACK_WAIT;
done := '1';
v.state := IDLE;
end if;
end if;
else
exception := '1';
dsisr(63 - 33) := m_in.invalid;
dsisr(63 - 36) := m_in.perm_error;
dsisr(63 - 38) := not r.load;
dsisr(63 - 44) := m_in.badtree;
dsisr(63 - 45) := m_in.rc_error;
v.state := IDLE;
end if;
end if;
end if;
end if;
if m_in.err = '1' then
exception := '1';
dsisr(63 - 33) := m_in.invalid;
dsisr(63 - 36) := m_in.perm_error;
dsisr(63 - 38) := not r.load;
dsisr(63 - 44) := m_in.badtree;
dsisr(63 - 45) := m_in.rc_error;
end if;
when TLBIE_WAIT =>
when TLBIE_WAIT =>
if m_in.done = '1' then
-- tlbie is finished
done := '1';
v.state := IDLE;
end if;
when LD_UPDATE =>
when LD_UPDATE =>
do_update := '1';
do_update := '1';
v.state := IDLE;
done := '1';
when SPR_CMPLT =>
when SPR_CMPLT =>
done := '1';
v.state := IDLE;
end case;
end case;
busy := '1';
if done = '1' or exception = '1' then
if r.state = IDLE or done = '1' then
v.state := IDLE;
busy := '0';
end if;
end if;
-- Note that l_in.valid is gated with busy inside execute1
-- Note that l_in.valid is gated with busy inside execute1
@ -450,6 +445,31 @@ begin
end if;
end if;
end if;
end if;
-- Work out whether we'll be busy next cycle
v.busy := '0';
v.wait_dcache := '0';
v.wait_mmu := '0';
case v.state is
when SECOND_REQ =>
v.busy := '1';
when ACK_WAIT =>
if v.last_dword = '0' or (v.load = '1' and v.update = '1') then
v.busy := '1';
else
v.wait_dcache := '1';
end if;
when MMU_LOOKUP =>
if v.instr_fault = '0' then
v.busy := '1';
else
v.wait_mmu := '1';
end if;
when TLBIE_WAIT =>
v.wait_mmu := '1';
when others =>
-- not busy next cycle
end case;
-- Update outputs to dcache
-- Update outputs to dcache
d_out.valid <= req;
d_out.valid <= req;
d_out.load <= v.load;
d_out.load <= v.load;