From 06ff486567aa2c7a9602cc55f9e8851491fa6a83 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 7 Sep 2023 22:22:31 +1000 Subject: [PATCH] icache: Restore primary opcode to instruction word The icache stores a predecoded insn_code value for each instruction, and so as to fit in 36 bits, omits the primary opcode (the most significant 6 bits) of each instruction. Previously, for valid instructions, the primary opcode field of the instruction delivered to decode1 was a part-representation of the insn_code value rather than the actual primary opcode. This adds a lookup table to compute the primary opcode from the insn_code and deliver it in the instruction words supplied to decode1. In order that each insn_code can be associated with a single primary opcode value, the various no-operation instructions with primary opcode 31 (the reserved no-ops and dss, dst and dstst) have been given a new insn_code, INSN_rnop, leaving INSN_nop for the preferred no-op (ori r0,r0,0). Signed-off-by: Paul Mackerras --- decode1.vhdl | 1 + decode_types.vhdl | 323 ++++++++++++++++++++++++++++++++++++++++++++-- icache.vhdl | 1 + predecode.vhdl | 22 ++-- 4 files changed, 325 insertions(+), 22 deletions(-) diff --git a/decode1.vhdl b/decode1.vhdl index e090d66..4163584 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -310,6 +310,7 @@ architecture behaviour of decode1 is INSN_rlwimi => (ALU, NONE, OP_RLC, RA, CONST_SH32, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), INSN_rlwinm => (ALU, NONE, OP_RLC, NONE, CONST_SH32, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), INSN_rlwnm => (ALU, NONE, OP_RLC, NONE, RB, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), + INSN_rnop => (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_sc => (ALU, NONE, OP_SC, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), INSN_setb => (ALU, NONE, OP_SETB, NONE, NONE, NONE, RT, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), INSN_slbia => (LDST, NONE, OP_TLBIE, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), diff --git a/decode_types.vhdl b/decode_types.vhdl index 9e7ef84..cfa4792 100644 --- a/decode_types.vhdl +++ b/decode_types.vhdl @@ -110,11 +110,12 @@ package decode_types is INSN_rldimi, INSN_rlwimi, INSN_rlwinm, + INSN_rnop, INSN_sc, INSN_setb, INSN_slbia, - INSN_sradi, - INSN_srawi, -- 80 + INSN_sradi, -- 80 + INSN_srawi, INSN_stbu, INSN_std, INSN_stdu, @@ -123,25 +124,27 @@ package decode_types is INSN_subfic, INSN_subfme, INSN_subfze, - INSN_sync, - INSN_tdi, -- 90 + INSN_sync, -- 90 + INSN_tdi, INSN_tlbsync, INSN_twi, INSN_wait, INSN_xori, INSN_xoris, + -- pad to 104 + INSN_061, INSN_062, INSN_063, INSN_064, INSN_065, INSN_066, INSN_067, -- Non-prefixed instructions that have a MLS:D prefixed form and -- their corresponding prefixed instructions. -- The non-prefixed versions have even indexes so that we can -- convert them to the prefixed version by setting bit 0 - INSN_addi, -- 96 + INSN_addi, -- 104 INSN_paddi, INSN_lbz, INSN_plbz, - INSN_lha, -- 100 + INSN_lha, INSN_plha, - INSN_lhz, + INSN_lhz, -- 110 INSN_plhz, INSN_lwz, INSN_plwz, @@ -149,11 +152,11 @@ package decode_types is INSN_pstb, INSN_sth, INSN_psth, - INSN_stw, -- 110 + INSN_stw, INSN_pstw, -- Slots for non-prefixed opcodes that are 8LS:D when prefixed - INSN_lhzu, -- 112 + INSN_lhzu, -- 120 INSN_plwa, INSN_op57, INSN_pld, @@ -161,8 +164,7 @@ package decode_types is INSN_pstd, -- pad to 128 to simplify comparison logic - INSN_076, INSN_077, - INSN_078, INSN_079, INSN_07a, INSN_07b, INSN_07c, INSN_07d, INSN_07e, INSN_07f, + INSN_07e, INSN_07f, -- The following instructions have an RB operand but don't access FPRs INSN_add, @@ -475,7 +477,306 @@ package decode_types is update => '0', reserve => '0', is_32bit => '0', is_signed => '0', rc => NONE, lr => '0', sgl_pipe => '0', repeat => NONE); + -- This function maps from insn_code values to primary opcode. + -- With this, we don't have to store the primary opcode of each instruction + -- in the icache if we are storing its insn_code. + function recode_primary_opcode(icode: insn_code) return std_ulogic_vector; + end decode_types; package body decode_types is + + function recode_primary_opcode(icode: insn_code) return std_ulogic_vector is + begin + case icode is + when INSN_addic => return "001100"; + when INSN_addic_dot => return "001101"; + when INSN_addi => return "001110"; + when INSN_addis => return "001111"; + when INSN_addpcis => return "010011"; + when INSN_andi_dot => return "011100"; + when INSN_andis_dot => return "011101"; + when INSN_attn => return "000000"; + when INSN_b => return "010010"; + when INSN_bc => return "010000"; + when INSN_brh => return "011111"; + when INSN_brw => return "011111"; + when INSN_brd => return "011111"; + when INSN_cmpi => return "001011"; + when INSN_cmpli => return "001010"; + when INSN_lbz => return "100010"; + when INSN_lbzu => return "100011"; + when INSN_lfd => return "110010"; + when INSN_lfdu => return "110011"; + when INSN_lfs => return "110000"; + when INSN_lfsu => return "110001"; + when INSN_lha => return "101010"; + when INSN_lhau => return "101011"; + when INSN_lhz => return "101000"; + when INSN_lhzu => return "101001"; + when INSN_lwz => return "100000"; + when INSN_lwzu => return "100001"; + when INSN_mulli => return "000111"; + when INSN_nop => return "011000"; + when INSN_ori => return "011000"; + when INSN_oris => return "011001"; + when INSN_rlwimi => return "010100"; + when INSN_rlwinm => return "010101"; + when INSN_rlwnm => return "010111"; + when INSN_sc => return "010001"; + when INSN_stb => return "100110"; + when INSN_stbu => return "100111"; + when INSN_stfd => return "110110"; + when INSN_stfdu => return "110111"; + when INSN_stfs => return "110100"; + when INSN_stfsu => return "110101"; + when INSN_sth => return "101100"; + when INSN_sthu => return "101101"; + when INSN_stw => return "100100"; + when INSN_stwu => return "100101"; + when INSN_subfic => return "001000"; + when INSN_tdi => return "000010"; + when INSN_twi => return "000011"; + when INSN_xori => return "011010"; + when INSN_xoris => return "011011"; + when INSN_maddhd => return "000100"; + when INSN_maddhdu => return "000100"; + when INSN_maddld => return "000100"; + when INSN_rldic => return "011110"; + when INSN_rldicl => return "011110"; + when INSN_rldicr => return "011110"; + when INSN_rldimi => return "011110"; + when INSN_rldcl => return "011110"; + when INSN_rldcr => return "011110"; + when INSN_ld => return "111010"; + when INSN_ldu => return "111010"; + when INSN_lwa => return "111010"; + when INSN_fdivs => return "111011"; + when INSN_fsubs => return "111011"; + when INSN_fadds => return "111011"; + when INSN_fsqrts => return "111011"; + when INSN_fres => return "111011"; + when INSN_fmuls => return "111011"; + when INSN_frsqrtes => return "111011"; + when INSN_fmsubs => return "111011"; + when INSN_fmadds => return "111011"; + when INSN_fnmsubs => return "111011"; + when INSN_fnmadds => return "111011"; + when INSN_std => return "111110"; + when INSN_stdu => return "111110"; + when INSN_fdiv => return "111111"; + when INSN_fsub => return "111111"; + when INSN_fadd => return "111111"; + when INSN_fsqrt => return "111111"; + when INSN_fsel => return "111111"; + when INSN_fre => return "111111"; + when INSN_fmul => return "111111"; + when INSN_frsqrte => return "111111"; + when INSN_fmsub => return "111111"; + when INSN_fmadd => return "111111"; + when INSN_fnmsub => return "111111"; + when INSN_fnmadd => return "111111"; + when INSN_prefix => return "000001"; + when INSN_op57 => return "111001"; + when INSN_op61 => return "111101"; + when INSN_add => return "011111"; + when INSN_addc => return "011111"; + when INSN_adde => return "011111"; + when INSN_addex => return "011111"; + when INSN_addg6s => return "011111"; + when INSN_addme => return "011111"; + when INSN_addze => return "011111"; + when INSN_and => return "011111"; + when INSN_andc => return "011111"; + when INSN_bperm => return "011111"; + when INSN_cbcdtd => return "011111"; + when INSN_cdtbcd => return "011111"; + when INSN_cmp => return "011111"; + when INSN_cmpb => return "011111"; + when INSN_cmpeqb => return "011111"; + when INSN_cmpl => return "011111"; + when INSN_cmprb => return "011111"; + when INSN_cntlzd => return "011111"; + when INSN_cntlzw => return "011111"; + when INSN_cnttzd => return "011111"; + when INSN_cnttzw => return "011111"; + when INSN_darn => return "011111"; + when INSN_dcbf => return "011111"; + when INSN_dcbst => return "011111"; + when INSN_dcbt => return "011111"; + when INSN_dcbtst => return "011111"; + when INSN_dcbz => return "011111"; + when INSN_divdeu => return "011111"; + when INSN_divweu => return "011111"; + when INSN_divde => return "011111"; + when INSN_divwe => return "011111"; + when INSN_divdu => return "011111"; + when INSN_divwu => return "011111"; + when INSN_divd => return "011111"; + when INSN_divw => return "011111"; + when INSN_eieio => return "011111"; + when INSN_eqv => return "011111"; + when INSN_extsb => return "011111"; + when INSN_extsh => return "011111"; + when INSN_extsw => return "011111"; + when INSN_extswsli => return "011111"; + when INSN_icbi => return "011111"; + when INSN_icbt => return "011111"; + when INSN_isel => return "011111"; + when INSN_lbarx => return "011111"; + when INSN_lbzcix => return "011111"; + when INSN_lbzux => return "011111"; + when INSN_lbzx => return "011111"; + when INSN_ldarx => return "011111"; + when INSN_ldbrx => return "011111"; + when INSN_ldcix => return "011111"; + when INSN_ldux => return "011111"; + when INSN_ldx => return "011111"; + when INSN_lfdx => return "011111"; + when INSN_lfdux => return "011111"; + when INSN_lfiwax => return "011111"; + when INSN_lfiwzx => return "011111"; + when INSN_lfsx => return "011111"; + when INSN_lfsux => return "011111"; + when INSN_lharx => return "011111"; + when INSN_lhaux => return "011111"; + when INSN_lhax => return "011111"; + when INSN_lhbrx => return "011111"; + when INSN_lhzcix => return "011111"; + when INSN_lhzux => return "011111"; + when INSN_lhzx => return "011111"; + when INSN_lwarx => return "011111"; + when INSN_lwaux => return "011111"; + when INSN_lwax => return "011111"; + when INSN_lwbrx => return "011111"; + when INSN_lwzcix => return "011111"; + when INSN_lwzux => return "011111"; + when INSN_lwzx => return "011111"; + when INSN_mcrxrx => return "011111"; + when INSN_mfcr => return "011111"; + when INSN_mfmsr => return "011111"; + when INSN_mfspr => return "011111"; + when INSN_modud => return "011111"; + when INSN_moduw => return "011111"; + when INSN_modsd => return "011111"; + when INSN_modsw => return "011111"; + when INSN_mtcrf => return "011111"; + when INSN_mtmsr => return "011111"; + when INSN_mtmsrd => return "011111"; + when INSN_mtspr => return "011111"; + when INSN_mulhd => return "011111"; + when INSN_mulhdu => return "011111"; + when INSN_mulhw => return "011111"; + when INSN_mulhwu => return "011111"; + when INSN_mulld => return "011111"; + when INSN_mullw => return "011111"; + when INSN_nand => return "011111"; + when INSN_neg => return "011111"; + when INSN_rnop => return "011111"; + when INSN_nor => return "011111"; + when INSN_or => return "011111"; + when INSN_orc => return "011111"; + when INSN_popcntb => return "011111"; + when INSN_popcntd => return "011111"; + when INSN_popcntw => return "011111"; + when INSN_prtyd => return "011111"; + when INSN_prtyw => return "011111"; + when INSN_setb => return "011111"; + when INSN_slbia => return "011111"; + when INSN_sld => return "011111"; + when INSN_slw => return "011111"; + when INSN_srad => return "011111"; + when INSN_sradi => return "011111"; + when INSN_sraw => return "011111"; + when INSN_srawi => return "011111"; + when INSN_srd => return "011111"; + when INSN_srw => return "011111"; + when INSN_stbcix => return "011111"; + when INSN_stbcx => return "011111"; + when INSN_stbux => return "011111"; + when INSN_stbx => return "011111"; + when INSN_stdbrx => return "011111"; + when INSN_stdcix => return "011111"; + when INSN_stdcx => return "011111"; + when INSN_stdux => return "011111"; + when INSN_stdx => return "011111"; + when INSN_stfdx => return "011111"; + when INSN_stfdux => return "011111"; + when INSN_stfiwx => return "011111"; + when INSN_stfsx => return "011111"; + when INSN_stfsux => return "011111"; + when INSN_sthbrx => return "011111"; + when INSN_sthcix => return "011111"; + when INSN_sthcx => return "011111"; + when INSN_sthux => return "011111"; + when INSN_sthx => return "011111"; + when INSN_stwbrx => return "011111"; + when INSN_stwcix => return "011111"; + when INSN_stwcx => return "011111"; + when INSN_stwux => return "011111"; + when INSN_stwx => return "011111"; + when INSN_subf => return "011111"; + when INSN_subfc => return "011111"; + when INSN_subfe => return "011111"; + when INSN_subfme => return "011111"; + when INSN_subfze => return "011111"; + when INSN_sync => return "011111"; + when INSN_td => return "011111"; + when INSN_tw => return "011111"; + when INSN_tlbie => return "011111"; + when INSN_tlbiel => return "011111"; + when INSN_tlbsync => return "011111"; + when INSN_wait => return "011111"; + when INSN_xor => return "011111"; + when INSN_bcctr => return "010011"; + when INSN_bclr => return "010011"; + when INSN_bctar => return "010011"; + when INSN_crand => return "010011"; + when INSN_crandc => return "010011"; + when INSN_creqv => return "010011"; + when INSN_crnand => return "010011"; + when INSN_crnor => return "010011"; + when INSN_cror => return "010011"; + when INSN_crorc => return "010011"; + when INSN_crxor => return "010011"; + when INSN_isync => return "010011"; + when INSN_mcrf => return "010011"; + when INSN_rfid => return "010011"; + when INSN_fcfids => return "111011"; + when INSN_fcfidus => return "111011"; + when INSN_fcmpu => return "111111"; + when INSN_fcmpo => return "111111"; + when INSN_mcrfs => return "111111"; + when INSN_ftdiv => return "111111"; + when INSN_ftsqrt => return "111111"; + when INSN_mtfsb => return "111111"; + when INSN_mtfsfi => return "111111"; + when INSN_fmrgow => return "111111"; + when INSN_fmrgew => return "111111"; + when INSN_mffs => return "111111"; + when INSN_mtfsf => return "111111"; + when INSN_fcpsgn => return "111111"; + when INSN_fneg => return "111111"; + when INSN_fmr => return "111111"; + when INSN_fnabs => return "111111"; + when INSN_fabs => return "111111"; + when INSN_frin => return "111111"; + when INSN_friz => return "111111"; + when INSN_frip => return "111111"; + when INSN_frim => return "111111"; + when INSN_frsp => return "111111"; + when INSN_fctiw => return "111111"; + when INSN_fctiwu => return "111111"; + when INSN_fctid => return "111111"; + when INSN_fcfid => return "111111"; + when INSN_fctidu => return "111111"; + when INSN_fcfidu => return "111111"; + when INSN_fctiwz => return "111111"; + when INSN_fctiwuz => return "111111"; + when INSN_fctidz => return "111111"; + when INSN_fctiduz => return "111111"; + when others => return "XXXXXX"; + end case; + end; + end decode_types; diff --git a/icache.vhdl b/icache.vhdl index e01eb35..21a7a24 100644 --- a/icache.vhdl +++ b/icache.vhdl @@ -621,6 +621,7 @@ begin insn := (others => '0'); elsif insn(ICWORDLEN - 1) = '0' then icode := insn_code'val(to_integer(unsigned(insn(ICWORDLEN-1 downto INSN_IMAGE_BITS)))); + insn(31 downto 26) := recode_primary_opcode(icode); end if; end if; i_out.insn <= insn(31 downto 0); diff --git a/predecode.vhdl b/predecode.vhdl index 27f80e1..0ab7427 100644 --- a/predecode.vhdl +++ b/predecode.vhdl @@ -220,9 +220,9 @@ architecture behaviour of predecoder is 2#0_11111_01001# => INSN_divd, -- divdo 2#0_01111_01011# => INSN_divw, 2#0_11111_01011# => INSN_divw, -- divwo - 2#0_11001_10110# => INSN_nop, -- dss - 2#0_01010_10110# => INSN_nop, -- dst - 2#0_01011_10110# => INSN_nop, -- dstst + 2#0_11001_10110# => INSN_rnop, -- dss + 2#0_01010_10110# => INSN_rnop, -- dst + 2#0_01011_10110# => INSN_rnop, -- dstst 2#0_11010_10110# => INSN_eieio, 2#0_01000_11100# => INSN_eqv, 2#0_11101_11010# => INSN_extsb, @@ -322,14 +322,14 @@ architecture behaviour of predecoder is 2#0_00011_01000# => INSN_neg, 2#0_10011_01000# => INSN_neg, -- nego -- next 8 are reserved no-op instructions - 2#0_10000_10010# => INSN_nop, - 2#0_10001_10010# => INSN_nop, - 2#0_10010_10010# => INSN_nop, - 2#0_10011_10010# => INSN_nop, - 2#0_10100_10010# => INSN_nop, - 2#0_10101_10010# => INSN_nop, - 2#0_10110_10010# => INSN_nop, - 2#0_10111_10010# => INSN_nop, + 2#0_10000_10010# => INSN_rnop, + 2#0_10001_10010# => INSN_rnop, + 2#0_10010_10010# => INSN_rnop, + 2#0_10011_10010# => INSN_rnop, + 2#0_10100_10010# => INSN_rnop, + 2#0_10101_10010# => INSN_rnop, + 2#0_10110_10010# => INSN_rnop, + 2#0_10111_10010# => INSN_rnop, 2#0_00011_11100# => INSN_nor, 2#0_01101_11100# => INSN_or, 2#0_01100_11100# => INSN_orc,