stall_out : out std_ulogic;
e_in : in Decode2ToExecute1Type;
+ l_in : in Loadstore1ToExecute1Type;
- i_in : in XicsToExecute1Type;
+ ext_irq_in : std_ulogic;
-- asynchronous
l_out : out Execute1ToLoadstore1Type;
e_out : out Execute1ToWritebackType;
+ dbg_msr_out : out std_ulogic_vector(63 downto 0);
+
icache_inval : out std_ulogic;
terminate_out : out std_ulogic
);
slow_op_rc : std_ulogic;
slow_op_oe : std_ulogic;
slow_op_xerc : xer_common_t;
+ ldst_nia : std_ulogic_vector(63 downto 0);
end record;
constant reg_type_init : reg_type :=
(e => Execute1ToWritebackInit, lr_update => '0',
mul_in_progress => '0', div_in_progress => '0', cntz_in_progress => '0',
slow_op_rc => '0', slow_op_oe => '0', slow_op_xerc => xerc_init,
- others => (others => '0'));
+ next_lr => (others => '0'), ldst_nia => (others => '0'), others => (others => '0'));
signal r, rin : reg_type;
signal ctrl: ctrl_t := (irq_state => WRITE_SRR0, others => (others => '0'));
signal ctrl_tmp: ctrl_t := (irq_state => WRITE_SRR0, others => (others => '0'));
signal right_shift, rot_clear_left, rot_clear_right: std_ulogic;
+ signal rot_sign_ext: std_ulogic;
signal rotator_result: std_ulogic_vector(63 downto 0);
signal rotator_carry: std_ulogic;
signal logical_result: std_ulogic_vector(63 downto 0);
OP_MFMSR => SUPER,
OP_MTMSRD => SUPER,
OP_RFID => SUPER,
+ OP_TLBIE => SUPER,
others => USER
);
arith => e_in.is_signed,
clear_left => rot_clear_left,
clear_right => rot_clear_right,
+ sign_ext_rs => rot_sign_ext,
result => rotator_result,
carry_out => rotator_carry
);
d_out => divider_to_x
);
+ dbg_msr_out <= ctrl.msr;
+
a_in <= r.e.write_data when EX1_BYPASS and e_in.bypass_data1 = '1' else e_in.read_data1;
b_in <= r.e.write_data when EX1_BYPASS and e_in.bypass_data2 = '1' else e_in.read_data2;
c_in <= r.e.write_data when EX1_BYPASS and e_in.bypass_data3 = '1' else e_in.read_data3;
ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#900#, 64));
report "IRQ valid: DEC";
irq_valid := '1';
- elsif i_in.irq = '1' then
+ elsif ext_irq_in = '1' then
ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#500#, 64));
report "IRQ valid: External";
irq_valid := '1';
icache_inval <= '0';
stall_out <= '0';
f_out <= Execute1ToFetch1TypeInit;
+ -- send MSR[IR] and ~MSR[PR] up to fetch1
+ f_out.virt_mode <= ctrl.msr(MSR_IR);
+ f_out.priv_mode <= not ctrl.msr(MSR_PR);
-- Next insn adder used in a couple of places
next_nia := std_ulogic_vector(unsigned(e_in.nia) + 4);
right_shift <= '1' when e_in.insn_type = OP_SHR else '0';
rot_clear_left <= '1' when e_in.insn_type = OP_RLC or e_in.insn_type = OP_RLCL else '0';
rot_clear_right <= '1' when e_in.insn_type = OP_RLC or e_in.insn_type = OP_RLCR else '0';
+ rot_sign_ext <= '1' when e_in.insn_type = OP_EXTSWSLI else '0';
ctrl_tmp.irq_state <= WRITE_SRR0;
exception := '0';
v.e.exc_write_reg := fast_spr_num(SPR_SRR0);
v.e.exc_write_data := e_in.nia;
- if ctrl.irq_state = WRITE_SRR1 then
- v.e.exc_write_reg := fast_spr_num(SPR_SRR1);
- v.e.exc_write_data := ctrl.srr1;
+ if ctrl.irq_state = WRITE_SRR1 then
+ v.e.exc_write_reg := fast_spr_num(SPR_SRR1);
+ v.e.exc_write_data := ctrl.srr1;
v.e.exc_write_enable := '1';
ctrl_tmp.msr(MSR_SF) <= '1';
ctrl_tmp.msr(MSR_EE) <= '0';
ctrl_tmp.msr(MSR_RI) <= '0';
ctrl_tmp.msr(MSR_LE) <= '1';
f_out.redirect <= '1';
+ f_out.virt_mode <= '0';
+ f_out.priv_mode <= '1';
f_out.redirect_nia <= ctrl.irq_nia;
v.e.valid := e_in.valid;
report "Writing SRR1: " & to_hstring(ctrl.srr1);
elsif irq_valid = '1' and e_in.valid = '1' then
-- we need two cycles to write srr0 and 1
- -- will need more when we have to write DSISR, DAR and HIER
+ -- will need more when we have to write HEIR
-- Don't deliver the interrupt until we have a valid instruction
-- coming in, so we have a valid NIA to put in SRR0.
exception := '1';
when OP_ILLEGAL =>
-- we need two cycles to write srr0 and 1
- -- will need more when we have to write DSISR, DAR and HIER
+ -- will need more when we have to write HEIR
illegal := '1';
when OP_SC =>
-- check bit 1 of the instruction is 1 so we know this is sc;
-- 0 would mean scv, so generate an illegal instruction interrupt
-- we need two cycles to write srr0 and 1
- -- will need more when we have to write DSISR, DAR and HIER
if e_in.insn(1) = '1' then
exception := '1';
exception_nextpc := '1';
when OP_RFID =>
f_out.redirect <= '1';
+ f_out.virt_mode <= b_in(MSR_IR) or b_in(MSR_PR);
+ f_out.priv_mode <= not b_in(MSR_PR);
f_out.redirect_nia <= a_in(63 downto 2) & "00"; -- srr0
-- Can't use msr_copy here because the partial function MSR
-- bits should be left unchanged, not zeroed.
when OP_MFSPR =>
report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
"=" & to_hstring(a_in);
+ result_en := '1';
if is_fast_spr(e_in.read_reg1) then
result := a_in;
if decode_spr_num(e_in.insn) = SPR_XER then
result := ctrl.tb;
when SPR_DEC =>
result := ctrl.dec;
- when others =>
- result := (others => '0');
+ when others =>
+ -- mfspr from unimplemented SPRs should be a nop in
+ -- supervisor mode and a program interrupt for user mode
+ result := c_in;
+ if ctrl.msr(MSR_PR) = '1' then
+ illegal := '1';
+ end if;
end case;
end if;
- result_en := '1';
when OP_MFCR =>
if e_in.insn(20) = '0' then
-- mfcr
when SPR_DEC =>
ctrl_tmp.dec <= c_in;
when others =>
+ -- mtspr to unimplemented SPRs should be a nop in
+ -- supervisor mode and a program interrupt for user mode
+ if ctrl.msr(MSR_PR) = '1' then
+ illegal := '1';
+ end if;
end case;
end if;
when OP_POPCNT =>
when OP_PRTY =>
result := parity_result;
result_en := '1';
- when OP_RLC | OP_RLCL | OP_RLCR | OP_SHL | OP_SHR =>
+ when OP_RLC | OP_RLCL | OP_RLCR | OP_SHL | OP_SHR | OP_EXTSWSLI =>
result := rotator_result;
if e_in.output_carry = '1' then
set_carry(v.e, rotator_carry, rotator_carry);
elsif e_in.valid = '1' then
-- instruction for other units, i.e. LDST
+ v.ldst_nia := e_in.nia;
v.e.valid := '0';
if e_in.unit = LDST then
lv.valid := '1';
v.e.write_data := result;
v.e.write_enable := result_en;
+ -- generate DSI or DSegI for load/store exceptions
+ -- or ISI or ISegI for instruction fetch exceptions
+ if l_in.exception = '1' then
+ ctrl_tmp.srr1 <= msr_copy(ctrl.msr);
+ if l_in.instr_fault = '0' then
+ if l_in.segment_fault = '0' then
+ ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#300#, 64));
+ else
+ ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#380#, 64));
+ end if;
+ else
+ if l_in.segment_fault = '0' then
+ ctrl_tmp.srr1(63 - 33) <= l_in.invalid;
+ ctrl_tmp.srr1(63 - 35) <= l_in.perm_error; -- noexec fault
+ ctrl_tmp.srr1(63 - 44) <= l_in.badtree;
+ ctrl_tmp.srr1(63 - 45) <= l_in.rc_error;
+ ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#400#, 64));
+ else
+ ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#480#, 64));
+ end if;
+ end if;
+ v.e.exc_write_enable := '1';
+ v.e.exc_write_reg := fast_spr_num(SPR_SRR0);
+ v.e.exc_write_data := r.ldst_nia;
+ report "ldst exception writing srr0=" & to_hstring(r.ldst_nia);
+ ctrl_tmp.irq_state <= WRITE_SRR1;
+ v.e.valid := '1'; -- complete the original load or store
+ end if;
+
-- Outputs to loadstore1 (async)
lv.op := e_in.insn_type;
+ lv.nia := e_in.nia;
lv.addr1 := a_in;
lv.addr2 := b_in;
lv.data := c_in;
lv.xerc := v.e.xerc;
lv.reserve := e_in.reserve;
lv.rc := e_in.rc;
+ lv.insn := e_in.insn;
-- decode l*cix and st*cix instructions here
if e_in.insn(31 downto 26) = "011111" and e_in.insn(10 downto 9) = "11" and
e_in.insn(5 downto 1) = "10101" then
lv.ci := '1';
end if;
+ lv.virt_mode := ctrl.msr(MSR_DR);
+ lv.priv_mode := not ctrl.msr(MSR_PR);
-- Update registers
rin <= v;