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 <paulus@ozlabs.org>
pull/422/head
Paul Mackerras 8 months ago
parent f59485f157
commit 06ff486567

@ -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),

@ -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;

@ -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);

@ -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,

Loading…
Cancel
Save