loadstore1: Generate alignment interrupts for unaligned larx/stcx
authorPaul Mackerras <paulus@ozlabs.org>
Fri, 21 Aug 2020 02:16:27 +0000 (12:16 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Sat, 22 Aug 2020 09:49:07 +0000 (19:49 +1000)
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 <paulus@ozlabs.org>
common.vhdl
execute1.vhdl
loadstore1.vhdl

index ec633231201e83f1e327b5305271de36bd882961..03211cea5807e8a2a53f0f2dd44c1d6738c567c5 100644 (file)
@@ -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;
index b9411c1a87fe13510680b792c64018848d3934a9..51ea5b077fa166eb101ea377d3123b878a518cf5 100644 (file)
@@ -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
index 6eb68046caa78d2518fd46fef9932d9c98b90774..e36025c4998981f2efa8541420ba61e0a78d8f91 100644 (file)
@@ -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;