decode1: Divide insn_code values into ranges to indicate register usage
authorPaul Mackerras <paulus@ozlabs.org>
Thu, 28 Jul 2022 09:00:04 +0000 (19:00 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 9 Aug 2022 09:52:08 +0000 (19:52 +1000)
This lets us compute r_out.reg_*_addr and r_out.read_2_enable values
without needing access to the primary opcode value.  We also have that
non-FP instructions are < 256.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
decode1.vhdl
decode_types.vhdl

index 9dd57d9dc9fb2de927da114ba01be7717db8675b..98c5b803575fdd61d28888c6e213f87452ed9885 100644 (file)
@@ -39,10 +39,6 @@ architecture behaviour of decode1 is
         ov_insn  : insn_code;
         spr_info : spr_id;
         ram_spr  : ram_spr_info;
-        fprs     : std_ulogic;
-        fprabc   : std_ulogic;
-        in3rc    : std_ulogic;
-        maybe_rb : std_ulogic;
     end record;
     constant dc0_t_init : dc0_t :=
         (f_in => IcacheToDecode1Init, ov_insn => INSN_illegal,
@@ -792,7 +788,9 @@ architecture behaviour of decode1 is
         INSN_wait        =>  (ALU,  NONE, OP_NOP,       NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
         INSN_xor         =>  (ALU,  NONE, OP_XOR,       NONE,       RB,          RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE),
         INSN_xori        =>  (ALU,  NONE, OP_XOR,       NONE,       CONST_UI,    RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
-        INSN_xoris       =>  (ALU,  NONE, OP_XOR,       NONE,       CONST_UI_HI, RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE)
+        INSN_xoris       =>  (ALU,  NONE, OP_XOR,       NONE,       CONST_UI_HI, RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+
+        others           =>  (NONE, NONE, OP_ILLEGAL,   NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE)
         );
 
     function decode_ram_spr(sprn : spr_num_t) return ram_spr_info is
@@ -959,22 +957,11 @@ begin
         when "000100" => -- 4
             -- major opcode 4, mostly VMX/VSX stuff but also some integer ops (madd*)
             v.override := not f_in.insn(5);
-            v.in3rc := '1';
-            v.maybe_rb := '1';
-
-        when "010111" => -- 23
-            -- rlwnm[.]
-            v.maybe_rb := '1';
 
         when "011111" => -- 31
             -- major opcode 31, lots of things
+            -- Use the first half of the row table for all columns
             v.use_row := '1';
-            v.maybe_rb := '1';
-
-            if HAS_FPU and std_match(f_in.insn(10 downto 1), "1----10111") then
-                -- lower half of column 23 has FP loads and stores
-                v.fprs := '1';
-            end if;
 
         when "010000" => -- 16
             -- Predict backward branches as taken, forward as untaken
@@ -990,8 +977,9 @@ begin
             -- Columns 8-15 and 24-31 don't have any valid instructions
             -- (where insn(5..1) is the column number).
             -- addpcis (column 2) is in the major table
-            -- Use the row table for columns 0-1 and 16-23 (mapped to 8-15)
-            -- Columns 4-7 in the row table are used for op 59 cols 12-15
+            -- Other valid columns are mapped to columns in the second
+            -- half of the row table: columns 0-1 are mapped to 16-17
+            -- and 16-23 are mapped to 24-31.
             v.override := f_in.insn(4);
             v.use_row := f_in.insn(5) or (not f_in.insn(3) and not f_in.insn(2));
 
@@ -1002,35 +990,26 @@ begin
                 v.ov_insn := INSN_nop;
             end if;
 
-        when "011110" => -- 30
-            v.maybe_rb := f_in.insn(4);
-
-        when "110100" | "110101" | "110110" | "110111" => -- 52, 53, 54, 55
-            -- stfd[u] and stfs[u]
-            if HAS_FPU then
-                v.fprs := '1';
-            end if;
-
         when "111011" => -- 59
             if HAS_FPU then
                 -- floating point operations, mostly single-precision
-                -- Use row table for columns 12-15, major table for 16-31
+                -- Columns 0-11 are illegal; columns 12-15 are mapped
+                -- to columns 20-23 in the second half of the row table,
+                -- and columns 16-31 are in the major table.
                 v.override := not f_in.insn(5) and (not f_in.insn(4) or not f_in.insn(3));
                 v.use_row := not f_in.insn(5);
-                v.in3rc := '1';
-                v.fprabc := '1';
-                v.fprs := '1';
-                v.maybe_rb := '1';
+            else
+                v.override := '1';
             end if;
 
         when "111111" => -- 63
             if HAS_FPU then
                 -- floating point operations, general and double-precision
+                -- Use columns 0-15 of the second half of the row table
+                -- for columns 0-15, and the major table for columns 16-31.
                 v.use_row := not f_in.insn(5);
-                v.in3rc := '1';
-                v.fprabc := '1';
-                v.fprs := '1';
-                v.maybe_rb := '1';
+            else
+                v.override := '1';
             end if;
 
         when others =>
@@ -1097,6 +1076,7 @@ begin
         variable vr : Decode1ToRegisterFileType;
         variable icode : insn_code;
         variable sprn : spr_num_t;
+        variable maybe_rb : std_ulogic;
     begin
         v := Decode1ToDecode2Init;
 
@@ -1124,15 +1104,32 @@ begin
         end if;
 
         -- Work out GPR/FPR read addresses
-        vr.reg_1_addr := dc0.fprabc & insn_ra(dc0.f_in.insn);
-        vr.reg_2_addr := dc0.fprabc & insn_rb(dc0.f_in.insn);
-        if dc0.in3rc = '1' then
-            vr.reg_3_addr := dc0.fprabc & insn_rcreg(dc0.f_in.insn);
-        else
-            vr.reg_3_addr := dc0.fprs & insn_rs(dc0.f_in.insn);
+        maybe_rb := '0';
+        vr.reg_1_addr := '0' & insn_ra(dc0.f_in.insn);
+        vr.reg_2_addr := '0' & insn_rb(dc0.f_in.insn);
+        vr.reg_3_addr := '0' & insn_rs(dc0.f_in.insn);
+        if icode >= INSN_first_rb then
+            maybe_rb := '1';
+            if icode < INSN_first_frs then
+                if icode >= INSN_first_rc then
+                    vr.reg_3_addr := '0' & insn_rcreg(dc0.f_in.insn);
+                end if;
+            else
+                -- access FRS operand
+                vr.reg_3_addr(5) := '1';
+                if icode >= INSN_first_frab then
+                    -- access FRA and/or FRB operands
+                    vr.reg_1_addr(5) := '1';
+                    vr.reg_2_addr(5) := '1';
+                end if;
+                if icode >= INSN_first_frabc then
+                    -- access FRC operand
+                    vr.reg_3_addr := '1' & insn_rcreg(dc0.f_in.insn);
+                end if;
+            end if;
         end if;
         vr.read_1_enable := dc0.f_in.valid and not dc0.f_in.fetch_failed;
-        vr.read_2_enable := dc0.f_in.valid and not dc0.f_in.fetch_failed and dc0.maybe_rb;
+        vr.read_2_enable := dc0.f_in.valid and not dc0.f_in.fetch_failed and maybe_rb;
         vr.read_3_enable := dc0.f_in.valid and not dc0.f_in.fetch_failed;
 
         v.reg_a := vr.reg_1_addr;
index 443d093605b2929143c591351bc9d9e81b634df3..dd2781e2485fb4750be32a3df0f12de2823bc400 100644 (file)
@@ -25,14 +25,15 @@ package decode_types is
                          OP_FETCH_FAILED
                         );
 
+    -- The following list is ordered in such a way that we can know some
+    -- things about which registers are accessed by an instruction by its place
+    -- in the list.  In other words we can decide whether an instruction
+    -- accesses FPRs and whether it has an RB operand by doing simple
+    -- comparisons of the insn_code for the instruction with a few constants.
     type insn_code is (
+        -- The following instructions don't have an RB operand or access FPRs
         INSN_illegal,
         INSN_fetch_fail,
-        INSN_add,
-        INSN_addc,
-        INSN_adde,
-        INSN_addex,
-        INSN_addg6s,
         INSN_addi,
         INSN_addic,
         INSN_addic_dot,
@@ -40,8 +41,6 @@ package decode_types is
         INSN_addme,
         INSN_addpcis,
         INSN_addze,
-        INSN_and,
-        INSN_andc,
         INSN_andi_dot,
         INSN_andis_dot,
         INSN_attn,
@@ -50,20 +49,14 @@ package decode_types is
         INSN_bcctr,
         INSN_bclr,
         INSN_bctar,
-        INSN_bperm,
         INSN_cbcdtd,
         INSN_cdtbcd,
-        INSN_cmp,
-        INSN_cmpb,
-        INSN_cmpeqb,
         INSN_cmpi,
-        INSN_cmpl,
         INSN_cmpli,
-        INSN_cmprb,
-        INSN_cntlzd,
         INSN_cntlzw,
-        INSN_cnttzd,
+        INSN_cntlzd,
         INSN_cnttzw,
+        INSN_cnttzd,
         INSN_crand,
         INSN_crandc,
         INSN_creqv,
@@ -73,242 +66,298 @@ package decode_types is
         INSN_crorc,
         INSN_crxor,
         INSN_darn,
-        INSN_dcbf,
-        INSN_dcbst,
-        INSN_dcbt,
-        INSN_dcbtst,
-        INSN_dcbz,
-        INSN_divd,
-        INSN_divde,
-        INSN_divdeu,
-        INSN_divdu,
-        INSN_divw,
-        INSN_divwe,
-        INSN_divweu,
-        INSN_divwu,
         INSN_eieio,
-        INSN_eqv,
         INSN_extsb,
         INSN_extsh,
         INSN_extsw,
         INSN_extswsli,
-        INSN_fabs,
-        INSN_fadd,
-        INSN_fadds,
-        INSN_fcfid,
-        INSN_fcfids,
-        INSN_fcfidu,
-        INSN_fcfidus,
-        INSN_fcmpo,
-        INSN_fcmpu,
-        INSN_fcpsgn,
-        INSN_fctid,
-        INSN_fctidu,
-        INSN_fctiduz,
-        INSN_fctidz,
-        INSN_fctiw,
-        INSN_fctiwu,
-        INSN_fctiwuz,
-        INSN_fctiwz,
-        INSN_fdiv,
-        INSN_fdivs,
-        INSN_fmadd,
-        INSN_fmadds,
-        INSN_fmr,
-        INSN_fmrgew,
-        INSN_fmrgow,
-        INSN_fmsub,
-        INSN_fmsubs,
-        INSN_fmul,
-        INSN_fmuls,
-        INSN_fnabs,
-        INSN_fneg,
-        INSN_fnmadd,
-        INSN_fnmadds,
-        INSN_fnmsub,
-        INSN_fnmsubs,
-        INSN_fre,
-        INSN_fres,
-        INSN_frim,
-        INSN_frin,
-        INSN_frip,
-        INSN_friz,
-        INSN_frsp,
-        INSN_frsqrte,
-        INSN_frsqrtes,
-        INSN_fsel,
-        INSN_fsqrt,
-        INSN_fsqrts,
-        INSN_fsub,
-        INSN_fsubs,
-        INSN_ftdiv,
-        INSN_ftsqrt,
-        INSN_icbi,
-        INSN_icbt,
-        INSN_isel,
         INSN_isync,
-        INSN_lbarx,
         INSN_lbz,
-        INSN_lbzcix,
         INSN_lbzu,
-        INSN_lbzux,
-        INSN_lbzx,
         INSN_ld,
-        INSN_ldarx,
-        INSN_ldbrx,
-        INSN_ldcix,
         INSN_ldu,
-        INSN_ldux,
-        INSN_ldx,
-        INSN_lfd,
-        INSN_lfdu,
-        INSN_lfdux,
-        INSN_lfdx,
-        INSN_lfiwax,
-        INSN_lfiwzx,
-        INSN_lfs,
-        INSN_lfsu,
-        INSN_lfsux,
-        INSN_lfsx,
         INSN_lha,
-        INSN_lharx,
         INSN_lhau,
-        INSN_lhaux,
-        INSN_lhax,
-        INSN_lhbrx,
         INSN_lhz,
-        INSN_lhzcix,
         INSN_lhzu,
-        INSN_lhzux,
-        INSN_lhzx,
         INSN_lwa,
-        INSN_lwarx,
-        INSN_lwaux,
-        INSN_lwax,
-        INSN_lwbrx,
         INSN_lwz,
-        INSN_lwzcix,
         INSN_lwzu,
-        INSN_lwzux,
-        INSN_lwzx,
-        INSN_maddhd,
-        INSN_maddhdu,
-        INSN_maddld,
         INSN_mcrf,
         INSN_mcrfs,
         INSN_mcrxrx,
         INSN_mfcr,
-        INSN_mffs,
         INSN_mfmsr,
         INSN_mfspr,
-        INSN_modsd,
-        INSN_modsw,
-        INSN_modud,
-        INSN_moduw,
         INSN_mtcrf,
         INSN_mtfsb,
-        INSN_mtfsf,
         INSN_mtfsfi,
         INSN_mtmsr,
         INSN_mtmsrd,
         INSN_mtspr,
-        INSN_mulhd,
-        INSN_mulhdu,
-        INSN_mulhw,
-        INSN_mulhwu,
-        INSN_mulld,
         INSN_mulli,
-        INSN_mullw,
-        INSN_nand,
         INSN_neg,
         INSN_nop,
-        INSN_nor,
-        INSN_or,
-        INSN_orc,
         INSN_ori,
         INSN_oris,
         INSN_popcntb,
-        INSN_popcntd,
         INSN_popcntw,
-        INSN_prtyd,
+        INSN_popcntd,
         INSN_prtyw,
+        INSN_prtyd,
         INSN_rfid,
-        INSN_rldcl,
-        INSN_rldcr,
         INSN_rldic,
         INSN_rldicl,
         INSN_rldicr,
         INSN_rldimi,
         INSN_rlwimi,
         INSN_rlwinm,
-        INSN_rlwnm,
         INSN_sc,
         INSN_setb,
         INSN_slbia,
-        INSN_sld,
-        INSN_slw,
-        INSN_srad,
         INSN_sradi,
-        INSN_sraw,
         INSN_srawi,
-        INSN_srd,
-        INSN_srw,
         INSN_stb,
+        INSN_stbu,
+        INSN_std,
+        INSN_stdu,
+        INSN_sth,
+        INSN_sthu,
+        INSN_stw,
+        INSN_stwu,
+        INSN_subfic,
+        INSN_subfme,
+        INSN_subfze,
+        INSN_sync,
+        INSN_tdi,
+        INSN_tlbsync,
+        INSN_twi,
+        INSN_wait,
+        INSN_xori,
+        INSN_xoris,
+
+        -- pad to 112 to simplify comparison logic
+        INSN_103,
+        INSN_104, INSN_105, INSN_106, INSN_107,
+        INSN_108, INSN_109, INSN_110, INSN_111,
+
+        -- The following instructions have an RB operand but don't access FPRs
+        INSN_add,
+        INSN_addc,
+        INSN_adde,
+        INSN_addex,
+        INSN_addg6s,
+        INSN_and,
+        INSN_andc,
+        INSN_bperm,
+        INSN_cmp,
+        INSN_cmpb,
+        INSN_cmpeqb,
+        INSN_cmpl,
+        INSN_cmprb,
+        INSN_dcbf,
+        INSN_dcbst,
+        INSN_dcbt,
+        INSN_dcbtst,
+        INSN_dcbz,
+        INSN_divd,
+        INSN_divdu,
+        INSN_divde,
+        INSN_divdeu,
+        INSN_divw,
+        INSN_divwu,
+        INSN_divwe,
+        INSN_divweu,
+        INSN_eqv,
+        INSN_icbi,
+        INSN_icbt,
+        INSN_isel,
+        INSN_lbarx,
+        INSN_lbzcix,
+        INSN_lbzux,
+        INSN_lbzx,
+        INSN_ldarx,
+        INSN_ldbrx,
+        INSN_ldcix,
+        INSN_ldx,
+        INSN_ldux,
+        INSN_lharx,
+        INSN_lhax,
+        INSN_lhaux,
+        INSN_lhbrx,
+        INSN_lhzcix,
+        INSN_lhzx,
+        INSN_lhzux,
+        INSN_lwarx,
+        INSN_lwax,
+        INSN_lwaux,
+        INSN_lwbrx,
+        INSN_lwzcix,
+        INSN_lwzx,
+        INSN_lwzux,
+        INSN_modsd,
+        INSN_modsw,
+        INSN_moduw,
+        INSN_modud,
+        INSN_mulhw,
+        INSN_mulhwu,
+        INSN_mulhd,
+        INSN_mulhdu,
+        INSN_mullw,
+        INSN_mulld,
+        INSN_nand,
+        INSN_nor,
+        INSN_or,
+        INSN_orc,
+        INSN_rldcl,
+        INSN_rldcr,
+        INSN_rlwnm,
+        INSN_slw,
+        INSN_sld,
+        INSN_sraw,
+        INSN_srad,
+        INSN_srw,
+        INSN_srd,
         INSN_stbcix,
         INSN_stbcx,
-        INSN_stbu,
-        INSN_stbux,
         INSN_stbx,
-        INSN_std,
+        INSN_stbux,
         INSN_stdbrx,
         INSN_stdcix,
         INSN_stdcx,
-        INSN_stdu,
-        INSN_stdux,
         INSN_stdx,
-        INSN_stfd,
-        INSN_stfdu,
-        INSN_stfdux,
-        INSN_stfdx,
-        INSN_stfiwx,
-        INSN_stfs,
-        INSN_stfsu,
-        INSN_stfsux,
-        INSN_stfsx,
-        INSN_sth,
+        INSN_stdux,
         INSN_sthbrx,
         INSN_sthcix,
         INSN_sthcx,
-        INSN_sthu,
-        INSN_sthux,
         INSN_sthx,
-        INSN_stw,
+        INSN_sthux,
         INSN_stwbrx,
         INSN_stwcix,
         INSN_stwcx,
-        INSN_stwu,
-        INSN_stwux,
         INSN_stwx,
+        INSN_stwux,
         INSN_subf,
         INSN_subfc,
         INSN_subfe,
-        INSN_subfic,
-        INSN_subfme,
-        INSN_subfze,
-        INSN_sync,
         INSN_td,
-        INSN_tdi,
         INSN_tlbie,
         INSN_tlbiel,
-        INSN_tlbsync,
         INSN_tw,
-        INSN_twi,
-        INSN_wait,
         INSN_xor,
-        INSN_xori,
-        INSN_xoris
+
+        -- pad to 224 to simplify comparison logic
+        INSN_215,
+        INSN_216, INSN_217, INSN_218, INSN_219,
+        INSN_220, INSN_221, INSN_222, INSN_223,
+
+        -- The following instructions have a third input addressed by RC
+        INSN_maddld,
+        INSN_maddhd,
+        INSN_maddhdu,
+
+        -- pad to 256 to simplify comparison logic
+        INSN_227,
+        INSN_228, INSN_229, INSN_230, INSN_231,
+        INSN_232, INSN_233, INSN_234, INSN_235,
+        INSN_236, INSN_237, INSN_238, INSN_239,
+        INSN_240, INSN_241, INSN_242, INSN_243,
+        INSN_244, INSN_245, INSN_246, INSN_247,
+        INSN_248, INSN_249, INSN_250, INSN_251,
+        INSN_252, INSN_253, INSN_254, INSN_255,
+
+        -- The following instructions access floating-point registers
+        -- These ones have an FRS operand, but RA/RB are GPRs
+        INSN_stfd,
+        INSN_stfdu,
+        INSN_stfs,
+        INSN_stfsu,
+        INSN_stfdux,
+        INSN_stfdx,
+        INSN_stfiwx,
+        INSN_stfsux,
+        INSN_stfsx,
+        -- These ones don't actually have an FRS operand (rather an FRT destination)
+        -- but are here so that all FP instructions are >= INST_first_frs.
+        INSN_lfd,
+        INSN_lfdu,
+        INSN_lfs,
+        INSN_lfsu,
+        INSN_lfdx,
+        INSN_lfdux,
+        INSN_lfiwax,
+        INSN_lfiwzx,
+        INSN_lfsx,
+        INSN_lfsux,
+        INSN_275, -- padding
+
+        -- The following instructions access FRA and/or FRB operands
+        INSN_fabs,
+        INSN_fadd,
+        INSN_fadds,
+        INSN_fcfid,
+        INSN_fcfids,
+        INSN_fcfidu,
+        INSN_fcfidus,
+        INSN_fcmpo,
+        INSN_fcmpu,
+        INSN_fcpsgn,
+        INSN_fctid,
+        INSN_fctidz,
+        INSN_fctidu,
+        INSN_fctiduz,
+        INSN_fctiw,
+        INSN_fctiwz,
+        INSN_fctiwu,
+        INSN_fctiwuz,
+        INSN_fdiv,
+        INSN_fdivs,
+        INSN_fmr,
+        INSN_fmrgew,
+        INSN_fmrgow,
+        INSN_fnabs,
+        INSN_fneg,
+        INSN_fre,
+        INSN_fres,
+        INSN_frim,
+        INSN_frin,
+        INSN_frip,
+        INSN_friz,
+        INSN_frsp,
+        INSN_frsqrte,
+        INSN_frsqrtes,
+        INSN_fsqrt,
+        INSN_fsqrts,
+        INSN_fsub,
+        INSN_fsubs,
+        INSN_ftdiv,
+        INSN_ftsqrt,
+        INSN_mffs,
+        INSN_mtfsf,
+
+        -- pad to 320
+        INSN_318, INSN_319,
+
+        -- The following instructions access FRA, FRB (possibly) and FRC operands
+        INSN_fmul,
+        INSN_fmuls,
+        INSN_fmadd,
+        INSN_fmadds,
+        INSN_fmsub,
+        INSN_fmsubs,
+        INSN_fnmadd,
+        INSN_fnmadds,
+        INSN_fnmsub,
+        INSN_fnmsubs,
+        INSN_fsel
         );
 
+    constant INSN_first_rb : insn_code := INSN_add;
+    constant INSN_first_rc : insn_code := INSN_maddld;
+    constant INSN_first_frs : insn_code := INSN_stfd;
+    constant INSN_first_frab : insn_code := INSN_fabs;
+    constant INSN_first_frabc : insn_code := INSN_fmul;
+
     type input_reg_a_t is (NONE, RA, RA_OR_ZERO, CIA, FRA);
     type input_reg_b_t is (NONE, RB, CONST_UI, CONST_SI, CONST_SI_HI, CONST_UI_HI, CONST_LI, CONST_BD,
                            CONST_DXHI4, CONST_DS, CONST_DQ, CONST_M1, CONST_SH, CONST_SH32, FRB);