core: Implement 32-bit mode
authorPaul Mackerras <paulus@ozlabs.org>
Sun, 16 Aug 2020 23:38:13 +0000 (09:38 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Thu, 20 Aug 2020 08:20:02 +0000 (18:20 +1000)
In 32-bit mode, effective addresses are truncated to 32 bits, both for
instruction fetches and data accesses, and CR0 is set for Rc=1 (record
form) instructions based on the lower 32 bits of the result rather
than all 64 bits.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
common.vhdl
execute1.vhdl
fetch1.vhdl
loadstore1.vhdl
writeback.vhdl

index 9ed07b30a38ac29167e548537732f1c88aafb5c9..ec633231201e83f1e327b5305271de36bd882961 100644 (file)
@@ -247,11 +247,12 @@ package common is
         virt_mode: std_ulogic;
         priv_mode: std_ulogic;
         big_endian: std_ulogic;
+        mode_32bit: std_ulogic;
        redirect_nia: std_ulogic_vector(63 downto 0);
     end record;
     constant Execute1ToFetch1Init : Execute1ToFetch1Type := (redirect => '0', virt_mode => '0',
                                                              priv_mode => '0', big_endian => '0',
-                                                             others => (others => '0'));
+                                                             mode_32bit => '0', others => (others => '0'));
 
     type Execute1ToLoadstore1Type is record
        valid : std_ulogic;
@@ -273,13 +274,14 @@ package common is
         rc : std_ulogic;                                -- set for stcx.
         virt_mode : std_ulogic;                         -- do translation through TLB
         priv_mode : std_ulogic;                         -- privileged mode (MSR[PR] = 0)
+        mode_32bit : std_ulogic;                        -- trim addresses to 32 bits
     end record;
     constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0',
                                                                      sign_extend => '0', update => '0', xerc => xerc_init,
                                                                      reserve => '0', rc => '0', virt_mode => '0', priv_mode => '0',
                                                                      nia => (others => '0'), insn => (others => '0'),
                                                                      addr1 => (others => '0'), addr2 => (others => '0'), data => (others => '0'), length => (others => '0'),
-                                                                     others => (others => '0'));
+                                                                     mode_32bit => '0', others => (others => '0'));
 
     type Loadstore1ToExecute1Type is record
         busy : std_ulogic;
@@ -376,6 +378,7 @@ package common is
     type Execute1ToWritebackType is record
        valid: std_ulogic;
        rc : std_ulogic;
+        mode_32bit : std_ulogic;
        write_enable : std_ulogic;
        write_reg: gspr_index_t;
        write_data: std_ulogic_vector(63 downto 0);
@@ -388,7 +391,7 @@ package common is
         exc_write_reg : gspr_index_t;
         exc_write_data : std_ulogic_vector(63 downto 0);
     end record;
-    constant Execute1ToWritebackInit : Execute1ToWritebackType := (valid => '0', rc => '0', write_enable => '0',
+    constant Execute1ToWritebackInit : Execute1ToWritebackType := (valid => '0', rc => '0', mode_32bit => '0', write_enable => '0',
                                                                   write_cr_enable => '0', exc_write_enable => '0',
                                                                   write_xerc_enable => '0', xerc => xerc_init,
                                    write_data => (others => '0'), write_cr_mask => (others => '0'),
index 99553ccfddd480651430997a7e15c89612b5fb37..b9411c1a87fe13510680b792c64018848d3934a9 100644 (file)
@@ -496,10 +496,11 @@ begin
        v.terminate := '0';
        icache_inval <= '0';
        v.busy := '0';
-        -- send MSR[IR], ~MSR[PR] and ~MSR[LE] up to fetch1
+        -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1
         v.f.virt_mode := ctrl.msr(MSR_IR);
         v.f.priv_mode := not ctrl.msr(MSR_PR);
         v.f.big_endian := not ctrl.msr(MSR_LE);
+        v.f.mode_32bit := not ctrl.msr(MSR_SF);
 
        -- Next insn adder used in a couple of places
        next_nia := std_ulogic_vector(unsigned(e_in.nia) + 4);
@@ -522,6 +523,8 @@ begin
             v.last_nia := e_in.nia;
         end if;
 
+        v.e.mode_32bit := not ctrl.msr(MSR_SF);
+
        if ctrl.irq_state = WRITE_SRR1 then
            v.e.exc_write_reg := fast_spr_num(SPR_SRR1);
            v.e.exc_write_data := ctrl.srr1;
@@ -742,6 +745,7 @@ begin
                 v.f.virt_mode := a_in(MSR_IR) or a_in(MSR_PR);
                 v.f.priv_mode := not a_in(MSR_PR);
                 v.f.big_endian := not a_in(MSR_LE);
+                v.f.mode_32bit := not a_in(MSR_SF);
                 -- Can't use msr_copy here because the partial function MSR
                 -- bits should be left unchanged, not zeroed.
                 ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31);
@@ -1165,6 +1169,7 @@ begin
             v.f.priv_mode := '1';
             -- XXX need an interrupt LE bit here, e.g. from LPCR
             v.f.big_endian := '0';
+            v.f.mode_32bit := '0';
         end if;
 
         if v.f.redirect = '1' then
@@ -1195,6 +1200,7 @@ begin
         end if;
         lv.virt_mode := ctrl.msr(MSR_DR);
         lv.priv_mode := not ctrl.msr(MSR_PR);
+        lv.mode_32bit := not ctrl.msr(MSR_SF);
 
        -- Update registers
        rin <= v;
index 63672cbbce69c77665b468221de048f2eb5dd34c..b100fb9d4181bb8cce101c29acc1ee56dec2573e 100644 (file)
@@ -38,6 +38,7 @@ architecture behaviour of fetch1 is
     type stop_state_t is (RUNNING, STOPPED, RESTARTING);
     type reg_internal_t is record
        stop_state: stop_state_t;
+        mode_32bit: std_ulogic;
     end record;
     signal r, r_next : Fetch1ToIcacheType;
     signal r_int, r_next_int : reg_internal_t;
@@ -53,6 +54,7 @@ begin
                     " IR:" & std_ulogic'image(r_next.virt_mode) &
                     " P:" & std_ulogic'image(r_next.priv_mode) &
                     " E:" & std_ulogic'image(r_next.big_endian) &
+                    " 32:" & std_ulogic'image(r_next_int.mode_32bit) &
                    " R:" & std_ulogic'image(e_in.redirect) & std_ulogic'image(d_in.redirect) &
                    " S:" & std_ulogic'image(stall_in) &
                    " T:" & std_ulogic'image(stop_in) &
@@ -84,13 +86,21 @@ begin
             v.priv_mode := '1';
             v.big_endian := '0';
            v_int.stop_state := RUNNING;
+            v_int.mode_32bit := '0';
        elsif e_in.redirect = '1' then
            v.nia := e_in.redirect_nia(63 downto 2) & "00";
+            if e_in.mode_32bit = '1' then
+                v.nia(63 downto 32) := (others => '0');
+            end if;
             v.virt_mode := e_in.virt_mode;
             v.priv_mode := e_in.priv_mode;
             v.big_endian := e_in.big_endian;
+            v_int.mode_32bit := e_in.mode_32bit;
         elsif d_in.redirect = '1' then
             v.nia := d_in.redirect_nia(63 downto 2) & "00";
+            if r_int.mode_32bit = '1' then
+                v.nia(63 downto 32) := (others => '0');
+            end if;
        elsif stall_in = '0' then
 
            -- For debug stop/step to work properly we need a little bit of
@@ -136,7 +146,11 @@ begin
            end case;
 
            if increment then
-               v.nia := std_logic_vector(unsigned(v.nia) + 4);
+                if r_int.mode_32bit = '0' then
+                    v.nia := std_ulogic_vector(unsigned(r.nia) + 4);
+                else
+                    v.nia := x"00000000" & std_ulogic_vector(unsigned(r.nia(31 downto 0)) + 4);
+                end if;
                 v.sequential := '1';
            end if;
        end if;
index 123c8ad7c30a9082bde73212c74e3dc4062557de..6eb68046caa78d2518fd46fef9932d9c98b90774 100644 (file)
@@ -84,6 +84,7 @@ architecture behave of loadstore1 is
         wait_mmu     : std_ulogic;
         do_update    : std_ulogic;
         extra_cycle  : std_ulogic;
+        mode_32bit   : std_ulogic;
     end record;
 
     type byte_sel_t is array(0 to 7) of std_ulogic;
@@ -272,13 +273,16 @@ begin
         exception := '0';
 
         if r.dwords_done = '1' or r.state = SECOND_REQ then
-            maddr := next_addr;
+            addr := next_addr;
             byte_sel := r.second_bytes;
         else
-            maddr := r.addr;
+            addr := r.addr;
             byte_sel := r.first_bytes;
         end if;
-        addr := maddr;
+        if r.mode_32bit = '1' then
+            addr(63 downto 32) := (others => '0');
+        end if;
+        maddr := addr;
 
         case r.state is
         when IDLE =>
@@ -365,6 +369,7 @@ begin
         -- Note that l_in.valid is gated with busy inside execute1
         if l_in.valid = '1' then
             v.addr := lsu_sum;
+            v.mode_32bit := l_in.mode_32bit;
             v.load := '0';
             v.dcbz := '0';
             v.tlbie := '0';
@@ -389,6 +394,9 @@ begin
             v.extra_cycle := '0';
 
             addr := lsu_sum;
+            if l_in.mode_32bit = '1' then
+                addr(63 downto 32) := (others => '0');
+            end if;
             maddr := l_in.addr2;    -- address from RB for tlbie
 
             -- XXX Temporary hack. Mark the op as non-cachable if the address
index d02a0b1d062f27de89f17a6a3e2786002aabe8e8..053a8baebd23011fb1b837890717c4d9e888ff6b 100644 (file)
@@ -99,8 +99,13 @@ begin
             -- Perform CR0 update for RC forms
             -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data
             if e_in.rc = '1' and e_in.write_enable = '1' then
-                sign := e_in.write_data(63);
-                zero := not (or e_in.write_data);
+                zero := not (or e_in.write_data(31 downto 0));
+                if e_in.mode_32bit = '0' then
+                    sign := e_in.write_data(63);
+                    zero := zero and not (or e_in.write_data(63 downto 32));
+                else
+                    sign := e_in.write_data(31);
+                end if;
                 c_out.write_cr_enable <= '1';
                 c_out.write_cr_mask <= num_to_fxm(0);
                 cf(3) := sign;