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 <paulus@ozlabs.org>
pull/239/head
Paul Mackerras 4 years ago
parent 2e7b371305
commit 033ee909fd

@ -247,11 +247,12 @@ package common is
virt_mode: std_ulogic; virt_mode: std_ulogic;
priv_mode: std_ulogic; priv_mode: std_ulogic;
big_endian: std_ulogic; big_endian: std_ulogic;
mode_32bit: std_ulogic;
redirect_nia: std_ulogic_vector(63 downto 0); redirect_nia: std_ulogic_vector(63 downto 0);
end record; end record;
constant Execute1ToFetch1Init : Execute1ToFetch1Type := (redirect => '0', virt_mode => '0', constant Execute1ToFetch1Init : Execute1ToFetch1Type := (redirect => '0', virt_mode => '0',
priv_mode => '0', big_endian => '0', priv_mode => '0', big_endian => '0',
others => (others => '0')); mode_32bit => '0', others => (others => '0'));


type Execute1ToLoadstore1Type is record type Execute1ToLoadstore1Type is record
valid : std_ulogic; valid : std_ulogic;
@ -273,13 +274,14 @@ package common is
rc : std_ulogic; -- set for stcx. rc : std_ulogic; -- set for stcx.
virt_mode : std_ulogic; -- do translation through TLB virt_mode : std_ulogic; -- do translation through TLB
priv_mode : std_ulogic; -- privileged mode (MSR[PR] = 0) priv_mode : std_ulogic; -- privileged mode (MSR[PR] = 0)
mode_32bit : std_ulogic; -- trim addresses to 32 bits
end record; end record;
constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0', constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0',
sign_extend => '0', update => '0', xerc => xerc_init, sign_extend => '0', update => '0', xerc => xerc_init,
reserve => '0', rc => '0', virt_mode => '0', priv_mode => '0', reserve => '0', rc => '0', virt_mode => '0', priv_mode => '0',
nia => (others => '0'), insn => (others => '0'), nia => (others => '0'), insn => (others => '0'),
addr1 => (others => '0'), addr2 => (others => '0'), data => (others => '0'), length => (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 type Loadstore1ToExecute1Type is record
busy : std_ulogic; busy : std_ulogic;
@ -376,6 +378,7 @@ package common is
type Execute1ToWritebackType is record type Execute1ToWritebackType is record
valid: std_ulogic; valid: std_ulogic;
rc : std_ulogic; rc : std_ulogic;
mode_32bit : std_ulogic;
write_enable : std_ulogic; write_enable : std_ulogic;
write_reg: gspr_index_t; write_reg: gspr_index_t;
write_data: std_ulogic_vector(63 downto 0); write_data: std_ulogic_vector(63 downto 0);
@ -388,7 +391,7 @@ package common is
exc_write_reg : gspr_index_t; exc_write_reg : gspr_index_t;
exc_write_data : std_ulogic_vector(63 downto 0); exc_write_data : std_ulogic_vector(63 downto 0);
end record; 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_cr_enable => '0', exc_write_enable => '0',
write_xerc_enable => '0', xerc => xerc_init, write_xerc_enable => '0', xerc => xerc_init,
write_data => (others => '0'), write_cr_mask => (others => '0'), write_data => (others => '0'), write_cr_mask => (others => '0'),

@ -496,10 +496,11 @@ begin
v.terminate := '0'; v.terminate := '0';
icache_inval <= '0'; icache_inval <= '0';
v.busy := '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.virt_mode := ctrl.msr(MSR_IR);
v.f.priv_mode := not ctrl.msr(MSR_PR); v.f.priv_mode := not ctrl.msr(MSR_PR);
v.f.big_endian := not ctrl.msr(MSR_LE); 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 insn adder used in a couple of places
next_nia := std_ulogic_vector(unsigned(e_in.nia) + 4); next_nia := std_ulogic_vector(unsigned(e_in.nia) + 4);
@ -522,6 +523,8 @@ begin
v.last_nia := e_in.nia; v.last_nia := e_in.nia;
end if; end if;


v.e.mode_32bit := not ctrl.msr(MSR_SF);

if ctrl.irq_state = WRITE_SRR1 then if ctrl.irq_state = WRITE_SRR1 then
v.e.exc_write_reg := fast_spr_num(SPR_SRR1); v.e.exc_write_reg := fast_spr_num(SPR_SRR1);
v.e.exc_write_data := ctrl.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.virt_mode := a_in(MSR_IR) or a_in(MSR_PR);
v.f.priv_mode := not a_in(MSR_PR); v.f.priv_mode := not a_in(MSR_PR);
v.f.big_endian := not a_in(MSR_LE); 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 -- Can't use msr_copy here because the partial function MSR
-- bits should be left unchanged, not zeroed. -- bits should be left unchanged, not zeroed.
ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31); ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31);
@ -1165,6 +1169,7 @@ begin
v.f.priv_mode := '1'; v.f.priv_mode := '1';
-- XXX need an interrupt LE bit here, e.g. from LPCR -- XXX need an interrupt LE bit here, e.g. from LPCR
v.f.big_endian := '0'; v.f.big_endian := '0';
v.f.mode_32bit := '0';
end if; end if;


if v.f.redirect = '1' then if v.f.redirect = '1' then
@ -1195,6 +1200,7 @@ begin
end if; end if;
lv.virt_mode := ctrl.msr(MSR_DR); lv.virt_mode := ctrl.msr(MSR_DR);
lv.priv_mode := not ctrl.msr(MSR_PR); lv.priv_mode := not ctrl.msr(MSR_PR);
lv.mode_32bit := not ctrl.msr(MSR_SF);


-- Update registers -- Update registers
rin <= v; rin <= v;

@ -38,6 +38,7 @@ architecture behaviour of fetch1 is
type stop_state_t is (RUNNING, STOPPED, RESTARTING); type stop_state_t is (RUNNING, STOPPED, RESTARTING);
type reg_internal_t is record type reg_internal_t is record
stop_state: stop_state_t; stop_state: stop_state_t;
mode_32bit: std_ulogic;
end record; end record;
signal r, r_next : Fetch1ToIcacheType; signal r, r_next : Fetch1ToIcacheType;
signal r_int, r_next_int : reg_internal_t; signal r_int, r_next_int : reg_internal_t;
@ -53,6 +54,7 @@ begin
" IR:" & std_ulogic'image(r_next.virt_mode) & " IR:" & std_ulogic'image(r_next.virt_mode) &
" P:" & std_ulogic'image(r_next.priv_mode) & " P:" & std_ulogic'image(r_next.priv_mode) &
" E:" & std_ulogic'image(r_next.big_endian) & " 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) & " R:" & std_ulogic'image(e_in.redirect) & std_ulogic'image(d_in.redirect) &
" S:" & std_ulogic'image(stall_in) & " S:" & std_ulogic'image(stall_in) &
" T:" & std_ulogic'image(stop_in) & " T:" & std_ulogic'image(stop_in) &
@ -84,13 +86,21 @@ begin
v.priv_mode := '1'; v.priv_mode := '1';
v.big_endian := '0'; v.big_endian := '0';
v_int.stop_state := RUNNING; v_int.stop_state := RUNNING;
v_int.mode_32bit := '0';
elsif e_in.redirect = '1' then elsif e_in.redirect = '1' then
v.nia := e_in.redirect_nia(63 downto 2) & "00"; 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.virt_mode := e_in.virt_mode;
v.priv_mode := e_in.priv_mode; v.priv_mode := e_in.priv_mode;
v.big_endian := e_in.big_endian; v.big_endian := e_in.big_endian;
v_int.mode_32bit := e_in.mode_32bit;
elsif d_in.redirect = '1' then elsif d_in.redirect = '1' then
v.nia := d_in.redirect_nia(63 downto 2) & "00"; 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 elsif stall_in = '0' then


-- For debug stop/step to work properly we need a little bit of -- For debug stop/step to work properly we need a little bit of
@ -136,7 +146,11 @@ begin
end case; end case;


if increment then 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'; v.sequential := '1';
end if; end if;
end if; end if;

@ -84,6 +84,7 @@ architecture behave of loadstore1 is
wait_mmu : std_ulogic; wait_mmu : std_ulogic;
do_update : std_ulogic; do_update : std_ulogic;
extra_cycle : std_ulogic; extra_cycle : std_ulogic;
mode_32bit : 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;
@ -272,13 +273,16 @@ begin
exception := '0'; exception := '0';


if r.dwords_done = '1' or r.state = SECOND_REQ then if r.dwords_done = '1' or r.state = SECOND_REQ then
maddr := next_addr; addr := next_addr;
byte_sel := r.second_bytes; byte_sel := r.second_bytes;
else else
maddr := r.addr; addr := r.addr;
byte_sel := r.first_bytes; byte_sel := r.first_bytes;
end if; end if;
addr := maddr; if r.mode_32bit = '1' then
addr(63 downto 32) := (others => '0');
end if;
maddr := addr;


case r.state is case r.state is
when IDLE => when IDLE =>
@ -365,6 +369,7 @@ begin
-- Note that l_in.valid is gated with busy inside execute1 -- Note that l_in.valid is gated with busy inside execute1
if l_in.valid = '1' then if l_in.valid = '1' then
v.addr := lsu_sum; v.addr := lsu_sum;
v.mode_32bit := l_in.mode_32bit;
v.load := '0'; v.load := '0';
v.dcbz := '0'; v.dcbz := '0';
v.tlbie := '0'; v.tlbie := '0';
@ -389,6 +394,9 @@ begin
v.extra_cycle := '0'; v.extra_cycle := '0';


addr := lsu_sum; 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 maddr := l_in.addr2; -- address from RB for tlbie


-- XXX Temporary hack. Mark the op as non-cachable if the address -- XXX Temporary hack. Mark the op as non-cachable if the address

@ -99,8 +99,13 @@ begin
-- Perform CR0 update for RC forms -- 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 -- 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 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(31 downto 0));
zero := not (or e_in.write_data); 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_enable <= '1';
c_out.write_cr_mask <= num_to_fxm(0); c_out.write_cr_mask <= num_to_fxm(0);
cf(3) := sign; cf(3) := sign;

Loading…
Cancel
Save