From 5ef5604b65f612ca4b5e3e945e3ceb3ed273bf28 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 31 Mar 2020 17:32:09 +1100 Subject: [PATCH] Add sc, illegal and decrementer exceptions and some supervisor state This adds the following exceptions: - 0x700 program check (for illegal instructions) - 0x900 decrementer - 0xc00 system call This also adds some supervisor state: - decremeter - msr (SPRG0/1 and SRR0/1 already exist as fast SPRs) It also adds some supporting instructions: - rfid - mtmsrd - mfmsr - sc MSR state is added but only EE is used in this patch set. Other bits are read/written but are not used at all. This adds a 2 stage state machine to execute1.vhdl. This state machine allows fast SPRS SRR0/1 to be written in different cycles. This state machine can be extended later to add DAR and DSISR SPR writing for more complex exceptions like page faults. Signed-off-by: Michael Neuling --- common.vhdl | 8 ++++ decode1.vhdl | 13 ++++++ decode_types.vhdl | 9 ++-- execute1.vhdl | 112 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 128 insertions(+), 14 deletions(-) diff --git a/common.vhdl b/common.vhdl index 1ed0606..9e4ef99 100644 --- a/common.vhdl +++ b/common.vhdl @@ -16,6 +16,7 @@ package common is constant SPR_LR : spr_num_t := 8; constant SPR_CTR : spr_num_t := 9; constant SPR_TB : spr_num_t := 268; + constant SPR_DEC : spr_num_t := 22; constant SPR_SRR0 : spr_num_t := 26; constant SPR_SRR1 : spr_num_t := 27; constant SPR_HSRR0 : spr_num_t := 314; @@ -62,9 +63,16 @@ package common is end record; constant xerc_init : xer_common_t := (others => '0'); + type irq_state_t is (WRITE_SRR0, WRITE_SRR1); + -- This needs to die... type ctrl_t is record tb: std_ulogic_vector(63 downto 0); + dec: std_ulogic_vector(63 downto 0); + msr: std_ulogic_vector(63 downto 0); + irq_state : irq_state_t; + irq_nia: std_ulogic_vector(63 downto 0); + srr1: std_ulogic_vector(63 downto 0); end record; type Fetch1ToIcacheType is record diff --git a/decode1.vhdl b/decode1.vhdl index 8a6804d..5230fa4 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -94,6 +94,7 @@ architecture behaviour of decode1 is 2#0011000001# => '1', -- crxor 2#0010010110# => '1', -- isync 2#0000000000# => '1', -- mcrf + 2#0000010010# => '1', -- rfid others => '0' ); @@ -109,6 +110,8 @@ architecture behaviour of decode1 is 2#100# => (ALU, OP_BCREG, SPR, SPR, NONE, SPR, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0'), -- isync 2#111# => (ALU, OP_ISYNC, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), + -- rfid + 2#101# => (ALU, OP_RFID, SPR, SPR, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), others => illegal_inst ); @@ -241,12 +244,14 @@ architecture behaviour of decode1 is -- 2#1000000000# mcrxr -- 2#1001000000# mcrxrx 2#0000010011# => (ALU, OP_MFCR, NONE, NONE, NONE, RT, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- mfcr/mfocrf + 2#0001010011# => (ALU, OP_MFMSR, NONE, NONE, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- mfmsr 2#0101010011# => (ALU, OP_MFSPR, SPR, NONE, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- mfspr 2#0100001001# => (ALU, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- modud 2#0100001011# => (ALU, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0'), -- moduw 2#1100001001# => (ALU, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0'), -- modsd 2#1100001011# => (ALU, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', NONE, '0', '0'), -- modsw 2#0010010000# => (ALU, OP_MTCRF, NONE, NONE, RS, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- mtcrf/mtocrf + 2#0010110010# => (ALU, OP_MTMSRD, NONE, NONE, RS, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- mtmsrd # ignore top bits and d 2#0111010011# => (ALU, OP_MTSPR, NONE, NONE, RS, SPR, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- mtspr 2#0001001001# => (ALU, OP_MUL_H64, RA, RB, NONE, RT, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0'), -- mulhd 2#0000001001# => (ALU, OP_MUL_H64, RA, RB, NONE, RT, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- mulhdu @@ -339,6 +344,7 @@ architecture behaviour of decode1 is -- op in out A out in out len ext pipe constant attn_instr : decode_rom_t := (ALU, OP_ATTN, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'); constant nop_instr : decode_rom_t := (ALU, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'); + constant sc_instr : decode_rom_t := (ALU, OP_SC, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'); constant sim_cfg_instr : decode_rom_t := (ALU, OP_SIM_CONFIG,NONE, NONE, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'); begin @@ -397,6 +403,9 @@ begin elsif std_match(f_in.insn, "01100000000000000000000000000000") then report "PPC_nop"; v.decode := nop_instr; + elsif std_match(f_in.insn, "010001--------------0000000---1-") then + report "PPC_sc"; + v.decode := sc_instr; elsif std_match(f_in.insn, "000001---------------0000000011-") then report "PPC_SIM_CONFIG"; v.decode := sim_cfg_instr; @@ -433,6 +442,10 @@ begin if is_fast_spr(v.ispr1) = '0' then v.decode.sgl_pipe := '1'; end if; + elsif v.decode.insn_type = OP_RFID then + report "PPC RFID"; + v.ispr1 := fast_spr_num(SPR_SRR0); + v.ispr2 := fast_spr_num(SPR_SRR1); end if; if flush_in = '1' then diff --git a/decode_types.vhdl b/decode_types.vhdl index 21d8b68..b2d9846 100644 --- a/decode_types.vhdl +++ b/decode_types.vhdl @@ -11,16 +11,15 @@ package decode_types is OP_DCBZ, OP_DIV, OP_DIVE, OP_EXTS, OP_EXTSWSLI, OP_ICBI, OP_ICBT, OP_ISEL, OP_ISYNC, OP_LOAD, OP_STORE, OP_MADDHD, OP_MADDHDU, OP_MADDLD, OP_MCRF, - OP_MCRXR, OP_MCRXRX, OP_MFCR, OP_MFSPR, OP_MOD, - OP_MTCRF, OP_MTSPR, OP_MUL_L64, + OP_MCRXR, OP_MCRXRX, OP_MFCR, OP_MFMSR, OP_MFSPR, OP_MOD, + OP_MTCRF, OP_MTMSRD, OP_MTSPR, OP_MUL_L64, OP_MUL_H64, OP_MUL_H32, OP_OR, - OP_POPCNT, OP_PRTY, - OP_RLC, OP_RLCL, OP_RLCR, OP_SETB, + OP_POPCNT, OP_PRTY, OP_RFID, + OP_RLC, OP_RLCL, OP_RLCR, OP_SC, OP_SETB, OP_SHL, OP_SHR, OP_SYNC, OP_TD, OP_TDI, OP_TW, OP_TWI, OP_XOR, OP_SIM_CONFIG ); - type input_reg_a_t is (NONE, RA, RA_OR_ZERO, SPR); type input_reg_b_t is (NONE, RB, CONST_UI, CONST_SI, CONST_SI_HI, CONST_UI_HI, CONST_LI, CONST_BD, CONST_DS, CONST_M1, CONST_SH, CONST_SH32, SPR); type input_reg_c_t is (NONE, RS); diff --git a/execute1.vhdl b/execute1.vhdl index 0d92266..d006002 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -53,9 +53,8 @@ architecture behaviour of execute1 is signal a_in, b_in, c_in : std_ulogic_vector(63 downto 0); - signal ctrl: ctrl_t := (others => (others => '0')); - signal ctrl_tmp: ctrl_t := (others => (others => '0')); - + 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 rotator_result: std_ulogic_vector(63 downto 0); signal rotator_carry: std_ulogic; @@ -112,6 +111,27 @@ architecture behaviour of execute1 is end case; end; + function msr_copy(msr: std_ulogic_vector(63 downto 0)) + return std_ulogic_vector is + variable msr_out: std_ulogic_vector(63 downto 0); + begin + -- ISA says this: + -- Defined MSR bits are classified as either full func- + -- tion or partial function. Full function MSR bits are + -- saved in SRR1 or HSRR1 when an interrupt other + -- than a System Call Vectored interrupt occurs and + -- restored by rfscv, rfid, or hrfid, while partial func- + -- tion MSR bits are not saved or restored. + -- Full function MSR bits lie in the range 0:32, 37:41, and + -- 48:63, and partial function MSR bits lie in the range + -- 33:36 and 42:47. + msr_out := (others => '0'); + msr_out(32 downto 0) := msr(32 downto 0); + msr_out(41 downto 37) := msr(41 downto 37); + msr_out(63 downto 48) := msr(63 downto 48); + return msr_out; + end; + begin rotator_0: entity work.rotator @@ -215,6 +235,8 @@ begin variable msb_a, msb_b : std_ulogic; variable a_lt : std_ulogic; variable lv : Execute1ToLoadstore1Type; + variable irq_valid : std_ulogic; + variable exception : std_ulogic; begin result := (others => '0'); result_with_carry := (others => '0'); @@ -341,6 +363,13 @@ begin ctrl_tmp <= ctrl; -- FIXME: run at 512MHz not core freq ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1); + ctrl_tmp.dec <= std_ulogic_vector(unsigned(ctrl.dec) - 1); + + irq_valid := '0'; + if ctrl.msr(63 - 48) = '1' and ctrl.dec(63) = '1' then + report "IRQ valid"; + irq_valid := '1'; + end if; terminate_out <= '0'; icache_inval <= '0'; @@ -355,7 +384,28 @@ begin 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'; - if e_in.valid = '1' then + ctrl_tmp.irq_state <= WRITE_SRR0; + exception := '0'; + + if ctrl.irq_state = WRITE_SRR1 then + v.e.write_reg := fast_spr_num(SPR_SRR1); + result := ctrl.srr1; + result_en := '1'; + ctrl_tmp.msr(63 - 48) <= '0'; -- clear EE + f_out.redirect <= '1'; + f_out.redirect_nia <= ctrl.irq_nia; + v.e.valid := '1'; + report "Writing SRR1: " & to_hstring(ctrl.srr1); + + elsif irq_valid = '1' then + -- we need two cycles to write srr0 and 1 + -- will need more when we have to write DSISR, DAR and HIER + exception := '1'; + ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#900#, 64)); + ctrl_tmp.srr1 <= msr_copy(ctrl.msr); + result := e_in.nia; + + elsif e_in.valid = '1' then v.e.valid := '1'; v.e.write_reg := e_in.write_reg; @@ -367,8 +417,25 @@ begin case_0: case e_in.insn_type is when OP_ILLEGAL => - terminate_out <= '1'; + -- we need two cycles to write srr0 and 1 + -- will need more when we have to write DSISR, DAR and HIER + exception := '1'; + ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#700#, 64)); + ctrl_tmp.srr1 <= msr_copy(ctrl.msr); + -- Since we aren't doing Hypervisor emulation assist (0xe40) we + -- set bit 44 to indicate we have an illegal + ctrl_tmp.srr1(63 - 44) <= '1'; + result := e_in.nia; report "illegal"; + when OP_SC => + -- FIXME Assume everything is SC (not SCV) for now + -- we need two cycles to write srr0 and 1 + -- will need more when we have to write DSISR, DAR and HIER + exception := '1'; + ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#C00#, 64)); + ctrl_tmp.srr1 <= msr_copy(ctrl.msr); + result := std_logic_vector(unsigned(e_in.nia) + 4); + report "sc"; when OP_ATTN => terminate_out <= '1'; report "ATTN"; @@ -477,6 +544,11 @@ begin f_out.redirect <= '1'; f_out.redirect_nia <= b_in(63 downto 2) & "00"; end if; + + when OP_RFID => + f_out.redirect <= '1'; + f_out.redirect_nia <= a_in(63 downto 2) & "00"; -- srr0 + ctrl_tmp.msr <= msr_copy(std_ulogic_vector(signed(b_in))); -- srr1 when OP_CMPB => result := ppc_cmpb(c_in, b_in); result_en := '1'; @@ -549,7 +621,12 @@ begin end if; end loop; end if; + when OP_MFMSR => + result := msr_copy(ctrl.msr); + result_en := '1'; when OP_MFSPR => + report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) & + "=" & to_hstring(a_in); if is_fast_spr(e_in.read_reg1) then result := a_in; if decode_spr_num(e_in.insn) = SPR_XER then @@ -566,6 +643,8 @@ begin case decode_spr_num(e_in.insn) is when SPR_TB => result := ctrl.tb; + when SPR_DEC => + result := ctrl.dec; when others => result := (others => '0'); end case; @@ -599,6 +678,9 @@ begin v.e.write_cr_mask := num_to_fxm(crnum); end if; v.e.write_cr_data := c_in(31 downto 0); + when OP_MTMSRD => + -- FIXME handle just the bits we need to. + ctrl_tmp.msr <= msr_copy(c_in); when OP_MTSPR => report "MTSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) & "=" & to_hstring(c_in); @@ -614,10 +696,12 @@ begin v.e.write_xerc_enable := '1'; end if; else --- TODO: Implement slow SPRs --- case decode_spr_num(e_in.insn) is --- when others => --- end case; + -- slow spr + case decode_spr_num(e_in.insn) is + when SPR_DEC => + ctrl_tmp.dec <= c_in; + when others => + end case; end if; when OP_POPCNT => result := popcnt_result; @@ -733,6 +817,16 @@ begin end if; end if; + if exception = '1' then + v.e.write_reg := fast_spr_num(SPR_SRR0); + if e_in.valid = '1' then + result_en := '1'; + ctrl_tmp.irq_state <= WRITE_SRR1; + stall_out <= '1'; + v.e.valid := '0'; + end if; + end if; + v.e.write_data := result; v.e.write_enable := result_en; -- 2.30.2