From 033ee909fdecc252d117863b111fbe7fa910d2a4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Aug 2020 09:38:13 +1000 Subject: [PATCH] core: Implement 32-bit mode 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 --- common.vhdl | 9 ++++++--- execute1.vhdl | 8 +++++++- fetch1.vhdl | 16 +++++++++++++++- loadstore1.vhdl | 14 +++++++++++--- writeback.vhdl | 9 +++++++-- 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/common.vhdl b/common.vhdl index 9ed07b3..ec63323 100644 --- a/common.vhdl +++ b/common.vhdl @@ -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'), diff --git a/execute1.vhdl b/execute1.vhdl index 99553cc..b9411c1 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -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; diff --git a/fetch1.vhdl b/fetch1.vhdl index 63672cb..b100fb9 100644 --- a/fetch1.vhdl +++ b/fetch1.vhdl @@ -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; diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 123c8ad..6eb6804 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -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 diff --git a/writeback.vhdl b/writeback.vhdl index d02a0b1..053a8ba 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -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;