From eee90a081516c3bbac9625e78be15652b79caa68 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 21 Aug 2020 12:16:27 +1000 Subject: [PATCH] loadstore1: Generate alignment interrupts for unaligned larx/stcx Load-and-reserve and store-conditional instructions are required to generate an alignment interrupt (0x600 vector) if their EA is not aligned. Implement this. Signed-off-by: Paul Mackerras --- common.vhdl | 1 + execute1.vhdl | 4 +++- loadstore1.vhdl | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/common.vhdl b/common.vhdl index ec63323..03211ce 100644 --- a/common.vhdl +++ b/common.vhdl @@ -286,6 +286,7 @@ package common is type Loadstore1ToExecute1Type is record busy : std_ulogic; exception : std_ulogic; + alignment : std_ulogic; invalid : std_ulogic; perm_error : std_ulogic; rc_error : std_ulogic; diff --git a/execute1.vhdl b/execute1.vhdl index b9411c1..51ea5b0 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -1139,7 +1139,9 @@ begin -- generate DSI or DSegI for load/store exceptions -- or ISI or ISegI for instruction fetch exceptions if l_in.exception = '1' then - if l_in.instr_fault = '0' then + if l_in.alignment = '1' then + v.f.redirect_nia := std_logic_vector(to_unsigned(16#600#, 64)); + elsif l_in.instr_fault = '0' then if l_in.segment_fault = '0' then v.f.redirect_nia := std_logic_vector(to_unsigned(16#300#, 64)); else diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 6eb6804..e36025c 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -78,6 +78,7 @@ architecture behave of loadstore1 is dar : std_ulogic_vector(63 downto 0); dsisr : std_ulogic_vector(31 downto 0); instr_fault : std_ulogic; + align_intr : std_ulogic; sprval : std_ulogic_vector(63 downto 0); busy : std_ulogic; wait_dcache : std_ulogic; @@ -171,6 +172,7 @@ begin variable dsisr : std_ulogic_vector(31 downto 0); variable mmu_mtspr : std_ulogic; variable itlb_fault : std_ulogic; + variable misaligned : std_ulogic; begin v := r; req := '0'; @@ -358,6 +360,7 @@ begin when TLBIE_WAIT => when COMPLETE => + exception := r.align_intr; end case; @@ -374,6 +377,7 @@ begin v.dcbz := '0'; v.tlbie := '0'; v.instr_fault := '0'; + v.align_intr := '0'; v.dwords_done := '0'; v.last_dword := '1'; v.write_reg := l_in.write_reg; @@ -411,6 +415,10 @@ begin v.first_bytes := byte_sel; v.second_bytes := long_sel(15 downto 8); + -- check alignment for larx/stcx + misaligned := or (std_ulogic_vector(unsigned(l_in.length(2 downto 0)) - 1) and addr(2 downto 0)); + v.align_intr := l_in.reserve and misaligned; + case l_in.op is when OP_STORE => req := '1'; @@ -420,6 +428,7 @@ begin -- Allow an extra cycle for RA update on loads v.extra_cycle := l_in.update; when OP_DCBZ => + v.align_intr := v.nc; req := '1'; v.dcbz := '1'; when OP_TLBIE => @@ -468,7 +477,9 @@ begin end case; if req = '1' then - if long_sel(15 downto 8) = "00000000" then + if v.align_intr = '1' then + v.state := COMPLETE; + elsif long_sel(15 downto 8) = "00000000" then v.state := ACK_WAIT; else v.state := SECOND_REQ; @@ -479,7 +490,7 @@ begin end if; -- Update outputs to dcache - d_out.valid <= req; + d_out.valid <= req and not v.align_intr; d_out.load <= v.load; d_out.dcbz <= v.dcbz; d_out.nc <= v.nc; @@ -526,6 +537,7 @@ begin -- update exception info back to execute1 e_out.busy <= busy; e_out.exception <= exception; + e_out.alignment <= r.align_intr; e_out.instr_fault <= r.instr_fault; e_out.invalid <= m_in.invalid; e_out.badtree <= m_in.badtree; @@ -534,7 +546,7 @@ begin e_out.segment_fault <= m_in.segerr; if exception = '1' and r.instr_fault = '0' then v.dar := addr; - if m_in.segerr = '0' then + if m_in.segerr = '0' and r.align_intr = '0' then v.dsisr := dsisr; end if; end if;