Add sc, illegal and decrementer exceptions and some supervisor state
authorMichael Neuling <mikey@neuling.org>
Tue, 31 Mar 2020 06:32:09 +0000 (17:32 +1100)
committerMichael Neuling <mikey@neuling.org>
Wed, 1 Apr 2020 01:02:33 +0000 (12:02 +1100)
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 <mikey@neuling.org>
common.vhdl
decode1.vhdl
decode_types.vhdl
execute1.vhdl

index 1ed060696f42b6a232479c186c65337e3368e4a2..9e4ef99e0428c7115a049a2b682625e11c34a985 100644 (file)
@@ -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
index 8a6804dcb39e48a31f764e8ab153ef7c7a788279..5230fa4f2c8f2277dadbe98929291939f37cc303 100644 (file)
@@ -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
index 21d8b686c94db56bb807b2b75a33673b9dfd7803..b2d9846d5decdfc463ba52334cc35c6c8b8ab290 100644 (file)
@@ -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);
index 0d92266b9f5946a0e9361764338ca3c9c02f2f73..d00600210075e9aa86c1077b85ae0fe3a96c3523 100644 (file)
@@ -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;