signal decode_rom_addr : insn_code;
signal decode : decode_rom_t;
+ type prefix_state_t is record
+ prefixed : std_ulogic;
+ prefix : std_ulogic_vector(25 downto 0);
+ pref_ia : std_ulogic_vector(3 downto 0);
+ end record;
+ constant prefix_state_init : prefix_state_t := (prefixed => '0', prefix => (others => '0'),
+ pref_ia => (others => '0'));
+
+ signal pr, pr_in : prefix_state_t;
+
signal fetch_failed : std_ulogic;
-- If we have an FPU, then it is used for integer divisions,
INSN_orc => (ALU, NONE, OP_OR, NONE, RB, RS, RA, '0', '0', '1', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE),
INSN_ori => (ALU, NONE, OP_OR, NONE, CONST_UI, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
INSN_oris => (ALU, NONE, OP_OR, NONE, CONST_UI_HI, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_paddi => (ALU, NONE, OP_ADD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_plbz => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_pld => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_plfd => (LDST, FPU, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, FRT, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_plfs => (LDST, FPU, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, FRT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE),
+ INSN_plha => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is2B, '0', '1', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_plhz => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_plwa => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '1', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_plwz => (LDST, NONE, OP_LOAD, RA0_OR_CIA, CONST_PSI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_pnop => (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_pstb => (LDST, NONE, OP_STORE, RA0_OR_CIA, CONST_PSI, RS, NONE, '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_pstd => (LDST, NONE, OP_STORE, RA0_OR_CIA, CONST_PSI, RS, NONE, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_pstfd => (LDST, FPU, OP_STORE, RA0_OR_CIA, CONST_PSI, FRS, NONE, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_pstfs => (LDST, FPU, OP_STORE, RA0_OR_CIA, CONST_PSI, FRS, NONE, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE),
+ INSN_psth => (LDST, NONE, OP_STORE, RA0_OR_CIA, CONST_PSI, RS, NONE, '0', '0', '0', '0', ZERO, '0', is2B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
+ INSN_pstw => (LDST, NONE, OP_STORE, RA0_OR_CIA, CONST_PSI, RS, NONE, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
INSN_popcntb => (ALU, NONE, OP_POPCNT, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
INSN_popcntd => (ALU, NONE, OP_POPCNT, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is8B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
INSN_popcntw => (ALU, NONE, OP_POPCNT, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', is4B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
if rst = '1' then
r <= Decode1ToDecode2Init;
fetch_failed <= '0';
+ pr <= prefix_state_init;
elsif flush_in = '1' then
r.valid <= '0';
fetch_failed <= '0';
+ pr <= prefix_state_init;
elsif stall_in = '0' then
r <= rin;
fetch_failed <= f_in.fetch_failed;
+ if f_in.valid = '1' then
+ pr <= pr_in;
+ end if;
end if;
if rst = '1' then
br.br_nia <= (others => '0');
variable icode : insn_code;
variable sprn : spr_num_t;
variable maybe_rb : std_ulogic;
+ variable pv : prefix_state_t;
+ variable icode_bits : std_ulogic_vector(9 downto 0);
+ variable valid_suffix : std_ulogic;
begin
v := Decode1ToDecode2Init;
+ pv := pr;
v.valid := f_in.valid;
v.nia := f_in.nia;
v.insn := f_in.insn;
+ v.prefix := pr.prefix;
+ v.prefixed := pr.prefixed;
v.stop_mark := f_in.stop_mark;
v.big_endian := f_in.big_endian;
end if;
icode := f_in.icode;
+ icode_bits := std_ulogic_vector(to_unsigned(insn_code'pos(icode), 10));
if f_in.fetch_failed = '1' then
- icode := INSN_fetch_fail;
+ icode_bits := std_ulogic_vector(to_unsigned(insn_code'pos(INSN_fetch_fail), 10));
-- Only send down a single OP_FETCH_FAILED
v.valid := not fetch_failed;
+ pv := prefix_state_init;
+
+ elsif pr.prefixed = '1' then
+ -- Check suffix value and convert to the prefixed instruction code
+ if pr.prefix(24) = '1' then
+ -- either pnop or illegal
+ icode_bits := std_ulogic_vector(to_unsigned(insn_code'pos(INSN_pnop), 10));
+ else
+ -- various load/store instructions
+ icode_bits(0) := '1';
+ end if;
+ valid_suffix := '0';
+ case pr.prefix(25 downto 23) is
+ when "000" => -- 8LS
+ if icode >= INSN_first_8ls and icode < INSN_first_rb then
+ valid_suffix := '1';
+ end if;
+ when "100" => -- MLS
+ if icode >= INSN_first_mls and icode < INSN_first_8ls then
+ valid_suffix := '1';
+ elsif icode >= INSN_first_fp_mls and icode < INSN_first_fp_nonmls then
+ valid_suffix := '1';
+ end if;
+ when "110" => -- MRR, i.e. pnop
+ if pr.prefix(22 downto 20) = "000" then
+ valid_suffix := '1';
+ end if;
+ when others =>
+ end case;
+ v.nia(5 downto 2) := pr.pref_ia;
+ v.prefixed := '1';
+ v.prefix := pr.prefix;
+ v.illegal_suffix := not valid_suffix;
+ pv := prefix_state_init;
+
+ elsif icode = INSN_prefix then
+ pv.prefixed := '1';
+ pv.pref_ia := f_in.nia(5 downto 2);
+ pv.prefix := f_in.insn(25 downto 0);
+ v.valid := '0';
+
end if;
- decode_rom_addr <= icode;
+ decode_rom_addr <= insn_code'val(to_integer(unsigned(icode_bits)));
if f_in.valid = '1' then
- report "Decode " & insn_code'image(icode) & " " & to_hstring(f_in.insn) &
- " at " & to_hstring(f_in.nia);
+ report "Decode " & insn_code'image(insn_code'val(to_integer(unsigned(icode_bits)))) & " " &
+ to_hstring(f_in.insn) & " at " & to_hstring(f_in.nia);
end if;
-- Branch predictor
br_target := std_ulogic_vector(signed(br.br_nia) + br.br_offset);
-- Work out GPR/FPR read addresses
+ -- Note that for prefixed instructions we are working this out based
+ -- only on the suffix.
maybe_rb := '0';
vr.reg_1_addr := '0' & insn_ra(f_in.insn);
vr.reg_2_addr := '0' & insn_rb(f_in.insn);
-- Update registers
rin <= v;
br_in <= bv;
+ pr_in <= pv;
-- Update outputs
d_out <= r;
-- The following instructions don't have an RB operand or access FPRs
INSN_illegal, -- 0
INSN_fetch_fail,
- INSN_addi,
+ INSN_prefix,
+ INSN_pnop,
INSN_addic,
INSN_addic_dot,
INSN_addis,
INSN_addme,
INSN_addpcis,
INSN_addze,
- INSN_andi_dot,
- INSN_andis_dot, -- 10
+ INSN_andi_dot, -- 10
+ INSN_andis_dot,
INSN_attn,
INSN_b,
INSN_bc,
INSN_bctar,
INSN_cbcdtd,
INSN_cdtbcd,
- INSN_cmpi,
- INSN_cmpli, -- 20
+ INSN_cmpi, -- 20
+ INSN_cmpli,
INSN_cntlzw,
INSN_cntlzd,
INSN_cnttzw,
INSN_crandc,
INSN_creqv,
INSN_crnand,
- INSN_crnor,
- INSN_cror, -- 30
+ INSN_crnor, -- 30
+ INSN_cror,
INSN_crorc,
INSN_crxor,
INSN_darn,
INSN_extsh,
INSN_extsw,
INSN_extswsli,
- INSN_isync,
- INSN_lbz, -- 40
+ INSN_isync, -- 40
INSN_lbzu,
INSN_ld,
INSN_ldu,
- INSN_lha,
INSN_lhau,
- INSN_lhz,
- INSN_lhzu,
INSN_lwa,
- INSN_lwz,
- INSN_lwzu, -- 50
+ INSN_lwzu,
INSN_mcrf,
INSN_mcrxrx,
INSN_mfcr,
- INSN_mfmsr,
+ INSN_mfmsr, -- 50
INSN_mfspr,
INSN_mtcrf,
INSN_mtmsr,
INSN_mtmsrd,
INSN_mtspr,
- INSN_mulli, -- 60
+ INSN_mulli,
INSN_neg,
INSN_nop,
INSN_ori,
- INSN_oris,
+ INSN_oris, -- 60
INSN_popcntb,
INSN_popcntw,
INSN_popcntd,
INSN_prtyw,
INSN_prtyd,
- INSN_rfid, -- 70
+ INSN_rfid,
INSN_rldic,
INSN_rldicl,
INSN_rldicr,
- INSN_rldimi,
+ INSN_rldimi, -- 70
INSN_rlwimi,
INSN_rlwinm,
INSN_sc,
INSN_setb,
INSN_slbia,
- INSN_sradi, -- 80
+ INSN_sradi,
INSN_srawi,
- INSN_stb,
INSN_stbu,
INSN_std,
- INSN_stdu,
- INSN_sth,
+ INSN_stdu, -- 80
INSN_sthu,
- INSN_stw,
INSN_stwu,
- INSN_subfic, -- 90
+ INSN_subfic,
INSN_subfme,
INSN_subfze,
INSN_sync,
INSN_tdi,
INSN_tlbsync,
INSN_twi,
- INSN_wait,
+ INSN_wait, -- 90
INSN_xori,
INSN_xoris,
+ INSN_93, -- padding
+ INSN_94,
+ INSN_95,
+
+ -- 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_paddi,
+ INSN_lbz,
+ INSN_plbz,
+ INSN_lha, -- 100
+ INSN_plha,
+ INSN_lhz,
+ INSN_plhz,
+ INSN_lwz,
+ INSN_plwz,
+ INSN_stb,
+ INSN_pstb,
+ INSN_sth,
+ INSN_psth,
+ INSN_stw, -- 110
+ INSN_pstw,
- -- pad to 112 to simplify comparison logic
- INSN_100, INSN_101, INSN_102, INSN_103,
- INSN_104, INSN_105, INSN_106, INSN_107,
- INSN_108, INSN_109, INSN_110, INSN_111,
+ -- Slots for non-prefixed opcodes that are 8LS:D when prefixed
+ INSN_lhzu, -- 112
+ INSN_plwa,
+ INSN_op57,
+ INSN_pld,
+ INSN_op61,
+ 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,
-- The following instructions have an RB operand but don't access FPRs
INSN_add,
INSN_addc,
- INSN_adde,
+ INSN_adde, -- 130
INSN_addex,
INSN_addg6s,
INSN_and,
INSN_andc,
INSN_bperm,
- INSN_cmp, -- 120
+ INSN_cmp,
INSN_cmpb,
INSN_cmpeqb,
INSN_cmpl,
- INSN_cmprb,
+ INSN_cmprb, -- 140
INSN_dcbf,
INSN_dcbst,
INSN_dcbt,
INSN_dcbtst,
INSN_dcbz,
- INSN_divd, -- 130
+ INSN_divd,
INSN_divdu,
INSN_divde,
INSN_divdeu,
- INSN_divw,
+ INSN_divw, -- 150
INSN_divwu,
INSN_divwe,
INSN_divweu,
INSN_eqv,
INSN_icbi,
- INSN_icbt, -- 140
+ INSN_icbt,
INSN_isel,
INSN_lbarx,
INSN_lbzcix,
- INSN_lbzux,
+ INSN_lbzux, -- 160
INSN_lbzx,
INSN_ldarx,
INSN_ldbrx,
INSN_ldcix,
INSN_ldx,
- INSN_ldux, -- 150
+ INSN_ldux,
INSN_lharx,
INSN_lhax,
INSN_lhaux,
- INSN_lhbrx,
+ INSN_lhbrx, -- 170
INSN_lhzcix,
INSN_lhzx,
INSN_lhzux,
INSN_lwarx,
INSN_lwax,
- INSN_lwaux, -- 160
+ INSN_lwaux,
INSN_lwbrx,
INSN_lwzcix,
INSN_lwzx,
- INSN_lwzux,
+ INSN_lwzux, -- 180
INSN_modsd,
INSN_modsw,
INSN_moduw,
INSN_modud,
INSN_mulhw,
- INSN_mulhwu, -- 170
+ INSN_mulhwu,
INSN_mulhd,
INSN_mulhdu,
INSN_mullw,
- INSN_mulld,
+ INSN_mulld, -- 190
INSN_nand,
INSN_nor,
INSN_or,
INSN_orc,
INSN_rldcl,
- INSN_rldcr, -- 180
+ INSN_rldcr,
INSN_rlwnm,
INSN_slw,
INSN_sld,
- INSN_sraw,
+ INSN_sraw, -- 200
INSN_srad,
INSN_srw,
INSN_srd,
INSN_stbcix,
INSN_stbcx,
- INSN_stbx, -- 190
+ INSN_stbx,
INSN_stbux,
INSN_stdbrx,
INSN_stdcix,
- INSN_stdcx,
+ INSN_stdcx, -- 210
INSN_stdx,
INSN_stdux,
INSN_sthbrx,
INSN_sthcix,
INSN_sthcx,
- INSN_sthx, -- 200
+ INSN_sthx,
INSN_sthux,
INSN_stwbrx,
INSN_stwcix,
- INSN_stwcx,
+ INSN_stwcx, -- 220
INSN_stwx,
INSN_stwux,
INSN_subf,
INSN_subfc,
INSN_subfe,
- INSN_td, -- 210
+ INSN_td,
INSN_tlbie,
INSN_tlbiel,
INSN_tw,
- INSN_xor,
+ INSN_xor, -- 230
- -- 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,
+ -- pad to 232 to simplify comparison logic
+ INSN_231,
-- The following instructions have a third input addressed by RC
INSN_maddld,
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_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_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,
+ -- They have an FRS operand, but RA/RB are GPRs
+
+ -- Non-prefixed floating-point loads and stores that have a MLS:D
+ -- prefixed form, and their corresponding prefixed instructions.
+ INSN_stfd, -- 256
+ INSN_pstfd,
INSN_stfs,
+ INSN_pstfs,
+ INSN_lfd, -- 260
+ INSN_plfd,
+ INSN_lfs,
+ INSN_plfs,
+
+ -- opcodes that can't have a prefix
+ INSN_stfdu, -- 264
INSN_stfsu,
- INSN_stfdux, -- 260
+ INSN_stfdux,
INSN_stfdx,
INSN_stfiwx,
INSN_stfsux,
- INSN_stfsx,
+ INSN_stfsx, -- 270
-- 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, -- 270
+ INSN_lfdux,
INSN_lfiwax,
INSN_lfiwzx,
INSN_lfsx,
INSN_lfsux,
-- These are here in order to keep the FP instructions together
INSN_mcrfs,
- INSN_mtfsb,
+ INSN_mtfsb, -- 280
INSN_mtfsfi,
- INSN_278, -- padding
- INSN_279,
+ INSN_282, -- padding
+ INSN_283,
+ INSN_284,
+ INSN_285,
+ INSN_286,
+ INSN_287,
-- The following instructions access FRA and/or FRB operands
- INSN_fabs, -- 280
+ INSN_fabs, -- 288
INSN_fadd,
- INSN_fadds,
+ INSN_fadds, -- 290
INSN_fcfid,
INSN_fcfids,
INSN_fcfidu,
INSN_fcmpo,
INSN_fcmpu,
INSN_fcpsgn,
- INSN_fctid, -- 290
+ INSN_fctid,
INSN_fctidz,
- INSN_fctidu,
+ INSN_fctidu, -- 300
INSN_fctiduz,
INSN_fctiw,
INSN_fctiwz,
INSN_fctiwuz,
INSN_fdiv,
INSN_fdivs,
- INSN_fmr, -- 300
+ INSN_fmr,
INSN_fmrgew,
- INSN_fmrgow,
+ INSN_fmrgow, -- 310
INSN_fnabs,
INSN_fneg,
INSN_fre,
INSN_frim,
INSN_frin,
INSN_frip,
- INSN_friz, -- 310
+ INSN_friz,
INSN_frsp,
- INSN_frsqrte,
+ INSN_frsqrte, -- 320
INSN_frsqrtes,
INSN_fsqrt,
INSN_fsqrts,
INSN_fsubs,
INSN_ftdiv,
INSN_ftsqrt,
- INSN_mffs, -- 320
+ INSN_mffs,
INSN_mtfsf,
- -- pad to 328
- INSN_322, INSN_323, INSN_324, INSN_325, INSN_326, INSN_327,
+ -- pad to 336
+ INSN_330, INSN_331, INSN_332, INSN_333, INSN_334, INSN_335,
-- The following instructions access FRA, FRB (possibly) and FRC operands
- INSN_fmul,
+ INSN_fmul, -- 336
INSN_fmuls,
- INSN_fmadd, -- 330
+ INSN_fmadd,
INSN_fmadds,
- INSN_fmsub,
+ INSN_fmsub, -- 340
INSN_fmsubs,
INSN_fnmadd,
INSN_fnmadds,
constant INSN_first_frs : insn_code := INSN_stfd;
constant INSN_first_frab : insn_code := INSN_fabs;
constant INSN_first_frabc : insn_code := INSN_fmul;
+ constant INSN_first_mls : insn_code := INSN_addi;
+ constant INSN_first_8ls : insn_code := INSN_lhzu;
+ constant INSN_first_fp_mls : insn_code := INSN_stfd;
+ constant INSN_first_fp_nonmls : insn_code := INSN_stfdu;
- type input_reg_a_t is (NONE, RA, RA_OR_ZERO, CIA, FRA);
+ type input_reg_a_t is (NONE, RA, RA_OR_ZERO, RA0_OR_CIA, 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);
+ CONST_DXHI4, CONST_DS, CONST_DQ, CONST_M1, CONST_SH, CONST_SH32, CONST_PSI, FRB);
type input_reg_c_t is (NONE, RS, RCR, FRC, FRS);
type output_reg_a_t is (NONE, RT, RA, FRT);
type rc_t is (NONE, ONE, RC, RCOE);