You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
microwatt/predecode.vhdl

635 lines
28 KiB
VHDL

-- Instruction pre-decoder for microwatt
-- One cycle latency. Does 'WIDTH' instructions in parallel.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.common.all;
use work.decode_types.all;
use work.insn_helpers.all;
entity predecoder is
generic (
HAS_FPU : boolean := true;
WIDTH : natural := 2;
ICODE_LEN : natural := 10;
IMAGE_LEN : natural := 26
);
port (
clk : in std_ulogic;
valid_in : in std_ulogic;
insns_in : in std_ulogic_vector(WIDTH * 32 - 1 downto 0);
icodes_out : out std_ulogic_vector(WIDTH * (ICODE_LEN + IMAGE_LEN) - 1 downto 0)
);
end entity predecoder;
architecture behaviour of predecoder is
type predecoder_rom_t is array(0 to 2047) of insn_code;
constant major_predecode_rom : predecoder_rom_t := (
2#001100_00000# to 2#001100_11111# => INSN_addic,
2#001101_00000# to 2#001101_11111# => INSN_addic_dot,
2#001110_00000# to 2#001110_11111# => INSN_addi,
2#001111_00000# to 2#001111_11111# => INSN_addis,
2#010011_00100# to 2#010011_00101# => INSN_addpcis,
2#011100_00000# to 2#011100_11111# => INSN_andi_dot,
2#011101_00000# to 2#011101_11111# => INSN_andis_dot,
2#000000_00000# => INSN_attn,
Improve timing of redirect_nia going from writeback to fetch1 This gets rid of the adder in writeback that computes redirect_nia. Instead, the main adder in the ALU is used to compute the branch target for relative branches. We now decode b and bc differently depending on the AA field, generating INSN_brel, INSN_babs, INSN_bcrel or INSN_bcabs as appropriate. Each one has a separate entry in the decode table in decode1; the *rel versions use CIA as the A input. The bclr/bcctr/bctar and rfid instructions now select ramspr_result for the main result mux to get the redirect address into ex1.e.write_data. For branches which are predicted taken but not actually taken, we need to redirect to the following instruction. We also need to do that for isync. We do this in the execute2 stage since whether or not to do it depends on the branch result. The next_nia computation is moved to the execute2 stage and comes in via a new leg on the secondary result multiplexer, making next_nia available ultimately in ex2.e.write_data. This also means that the next_nia leg of the primary result multiplexer is gone. Incrementing last_nia by 4 for sc (so that SRR0 points to the following instruction) is also moved to execute2. Writing CIA+4 to LR was previously done through the main result multiplexer. Now it comes in explicitly in the ramspr write logic. Overall this removes the br_offset and abs_br fields and the logic to add br_offset and next_nia, and one leg of the primary result multiplexer, at the cost of a few extra control signals between execute1 and execute2 and some multiplexing for the ramspr write side and an extra input on the secondary result multiplexer. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
8 months ago
2#010010_00000# to 2#010010_00001# => INSN_brel,
2#010010_00010# to 2#010010_00011# => INSN_babs,
2#010010_00100# to 2#010010_00101# => INSN_brel,
2#010010_00110# to 2#010010_00111# => INSN_babs,
2#010010_01000# to 2#010010_01001# => INSN_brel,
2#010010_01010# to 2#010010_01011# => INSN_babs,
2#010010_01100# to 2#010010_01101# => INSN_brel,
2#010010_01110# to 2#010010_01111# => INSN_babs,
2#010010_10000# to 2#010010_10001# => INSN_brel,
2#010010_10010# to 2#010010_10011# => INSN_babs,
2#010010_10100# to 2#010010_10101# => INSN_brel,
2#010010_10110# to 2#010010_10111# => INSN_babs,
2#010010_11000# to 2#010010_11001# => INSN_brel,
2#010010_11010# to 2#010010_11011# => INSN_babs,
2#010010_11100# to 2#010010_11101# => INSN_brel,
2#010010_11110# to 2#010010_11111# => INSN_babs,
2#010000_00000# to 2#010000_00001# => INSN_bcrel,
2#010000_00010# to 2#010000_00011# => INSN_bcabs,
2#010000_00100# to 2#010000_00101# => INSN_bcrel,
2#010000_00110# to 2#010000_00111# => INSN_bcabs,
2#010000_01000# to 2#010000_01001# => INSN_bcrel,
2#010000_01010# to 2#010000_01011# => INSN_bcabs,
2#010000_01100# to 2#010000_01101# => INSN_bcrel,
2#010000_01110# to 2#010000_01111# => INSN_bcabs,
2#010000_10000# to 2#010000_10001# => INSN_bcrel,
2#010000_10010# to 2#010000_10011# => INSN_bcabs,
2#010000_10100# to 2#010000_10101# => INSN_bcrel,
2#010000_10110# to 2#010000_10111# => INSN_bcabs,
2#010000_11000# to 2#010000_11001# => INSN_bcrel,
2#010000_11010# to 2#010000_11011# => INSN_bcabs,
2#010000_11100# to 2#010000_11101# => INSN_bcrel,
2#010000_11110# to 2#010000_11111# => INSN_bcabs,
2#001011_00000# to 2#001011_11111# => INSN_cmpi,
2#001010_00000# to 2#001010_11111# => INSN_cmpli,
2#100010_00000# to 2#100010_11111# => INSN_lbz,
2#100011_00000# to 2#100011_11111# => INSN_lbzu,
2#110010_00000# to 2#110010_11111# => INSN_lfd,
2#110011_00000# to 2#110011_11111# => INSN_lfdu,
2#110000_00000# to 2#110000_11111# => INSN_lfs,
2#110001_00000# to 2#110001_11111# => INSN_lfsu,
2#101010_00000# to 2#101010_11111# => INSN_lha,
2#101011_00000# to 2#101011_11111# => INSN_lhau,
2#101000_00000# to 2#101000_11111# => INSN_lhz,
2#101001_00000# to 2#101001_11111# => INSN_lhzu,
2#100000_00000# to 2#100000_11111# => INSN_lwz,
2#100001_00000# to 2#100001_11111# => INSN_lwzu,
2#000111_00000# to 2#000111_11111# => INSN_mulli,
2#011000_00000# to 2#011000_11111# => INSN_ori,
2#011001_00000# to 2#011001_11111# => INSN_oris,
2#010100_00000# to 2#010100_11111# => INSN_rlwimi,
2#010101_00000# to 2#010101_11111# => INSN_rlwinm,
2#010111_00000# to 2#010111_11111# => INSN_rlwnm,
2#010001_00000# to 2#010001_11111# => INSN_sc,
2#100110_00000# to 2#100110_11111# => INSN_stb,
2#100111_00000# to 2#100111_11111# => INSN_stbu,
2#110110_00000# to 2#110110_11111# => INSN_stfd,
2#110111_00000# to 2#110111_11111# => INSN_stfdu,
2#110100_00000# to 2#110100_11111# => INSN_stfs,
2#110101_00000# to 2#110101_11111# => INSN_stfsu,
2#101100_00000# to 2#101100_11111# => INSN_sth,
2#101101_00000# to 2#101101_11111# => INSN_sthu,
2#100100_00000# to 2#100100_11111# => INSN_stw,
2#100101_00000# to 2#100101_11111# => INSN_stwu,
2#001000_00000# to 2#001000_11111# => INSN_subfic,
2#000010_00000# to 2#000010_11111# => INSN_tdi,
2#000011_00000# to 2#000011_11111# => INSN_twi,
2#011010_00000# to 2#011010_11111# => INSN_xori,
2#011011_00000# to 2#011011_11111# => INSN_xoris,
-- major opcode 4
2#000100_10000# => INSN_maddhd,
2#000100_10001# => INSN_maddhdu,
2#000100_10011# => INSN_maddld,
-- major opcode 30
2#011110_01000# to 2#011110_01001# => INSN_rldic,
2#011110_01010# to 2#011110_01011# => INSN_rldic,
2#011110_00000# to 2#011110_00001# => INSN_rldicl,
2#011110_00010# to 2#011110_00011# => INSN_rldicl,
2#011110_00100# to 2#011110_00101# => INSN_rldicr,
2#011110_00110# to 2#011110_00111# => INSN_rldicr,
2#011110_01100# to 2#011110_01101# => INSN_rldimi,
2#011110_01110# to 2#011110_01111# => INSN_rldimi,
2#011110_10000# to 2#011110_10001# => INSN_rldcl,
2#011110_10010# to 2#011110_10011# => INSN_rldcr,
-- major opcode 58
2#111010_00000# => INSN_ld,
2#111010_00001# => INSN_ldu,
2#111010_00010# => INSN_lwa,
2#111010_00100# => INSN_ld,
2#111010_00101# => INSN_ldu,
2#111010_00110# => INSN_lwa,
2#111010_01000# => INSN_ld,
2#111010_01001# => INSN_ldu,
2#111010_01010# => INSN_lwa,
2#111010_01100# => INSN_ld,
2#111010_01101# => INSN_ldu,
2#111010_01110# => INSN_lwa,
2#111010_10000# => INSN_ld,
2#111010_10001# => INSN_ldu,
2#111010_10010# => INSN_lwa,
2#111010_10100# => INSN_ld,
2#111010_10101# => INSN_ldu,
2#111010_10110# => INSN_lwa,
2#111010_11000# => INSN_ld,
2#111010_11001# => INSN_ldu,
2#111010_11010# => INSN_lwa,
2#111010_11100# => INSN_ld,
2#111010_11101# => INSN_ldu,
2#111010_11110# => INSN_lwa,
-- major opcode 59
2#111011_00100# to 2#111011_00101# => INSN_fdivs,
2#111011_01000# to 2#111011_01001# => INSN_fsubs,
2#111011_01010# to 2#111011_01011# => INSN_fadds,
2#111011_01100# to 2#111011_01101# => INSN_fsqrts,
2#111011_10000# to 2#111011_10001# => INSN_fres,
2#111011_10010# to 2#111011_10011# => INSN_fmuls,
2#111011_10100# to 2#111011_10101# => INSN_frsqrtes,
2#111011_11000# to 2#111011_11001# => INSN_fmsubs,
2#111011_11010# to 2#111011_11011# => INSN_fmadds,
2#111011_11100# to 2#111011_11101# => INSN_fnmsubs,
2#111011_11110# to 2#111011_11111# => INSN_fnmadds,
-- major opcode 62
2#111110_00000# => INSN_std,
2#111110_00001# => INSN_stdu,
2#111110_00100# => INSN_std,
2#111110_00101# => INSN_stdu,
2#111110_01000# => INSN_std,
2#111110_01001# => INSN_stdu,
2#111110_01100# => INSN_std,
2#111110_01101# => INSN_stdu,
2#111110_10000# => INSN_std,
2#111110_10001# => INSN_stdu,
2#111110_10100# => INSN_std,
2#111110_10101# => INSN_stdu,
2#111110_11000# => INSN_std,
2#111110_11001# => INSN_stdu,
2#111110_11100# => INSN_std,
2#111110_11101# => INSN_stdu,
-- major opcode 63
2#111111_00100# to 2#111111_00101# => INSN_fdiv,
2#111111_01000# to 2#111111_01001# => INSN_fsub,
2#111111_01010# to 2#111111_01011# => INSN_fadd,
2#111111_01100# to 2#111111_01101# => INSN_fsqrt,
2#111111_01110# to 2#111111_01111# => INSN_fsel,
2#111111_10000# to 2#111111_10001# => INSN_fre,
2#111111_10010# to 2#111111_10011# => INSN_fmul,
2#111111_10100# to 2#111111_10101# => INSN_frsqrte,
2#111111_11000# to 2#111111_11001# => INSN_fmsub,
2#111111_11010# to 2#111111_11011# => INSN_fmadd,
2#111111_11100# to 2#111111_11101# => INSN_fnmsub,
2#111111_11110# to 2#111111_11111# => INSN_fnmadd,
Decode prefixed instructions This adds logic to do basic decoding of the prefixed instructions defined in PowerISA v3.1B which are in the SFFS (Scalar Fixed plus Floating-Point Subset) compliancy subset. In PowerISA v3.1B SFFS, there are 14 prefixed load/store instructions plus the prefixed no-op instruction (pnop). The prefixed load/store instructions all use an extended version of D-form, which has an extra 18 bits of displacement in the prefix, plus an 'R' bit which enables PC-relative addressing. When decode1 sees an instruction word where the insn_code is INSN_prefix (i.e. the primary opcode was 1), it stores the prefix word and sends nothing down to decode2 in that cycle. When the next valid instruction word arrives, it is interpreted as a suffix, meaning that its insn_code gets modified before being used to look up the decode table. The insn_code values are rearranged so that the values for instructions which are the suffix of a valid prefixed instruction are all at even indexes, and the corresponding prefixed instructions follow immediately, so that an insn_code value can be converted to the corresponding prefixed value by setting the LSB of the insn_code value. There are two prefixed instructions, pld and pstd, for which the suffix is not a valid SFFS instruction by itself, so these have been given dummy insn_code values which decode as illegal (INSN_op57 and INSN_op61). For a prefixed instruction, decode1 examines the type and subtype fields of the prefix and checks that the suffix is valid for the type and subtype. This check doesn't affect which entry of the decode table is used; the result is passed down to decode2, and will in future be acted upon in execute1. The instruction address passed down to decode2 is the address of the prefix. To enable this, part of the instruction address is saved when the prefix is seen, and then the instruction address received from icache is partly overlaid by the saved prefix address. Because prefixed instructions are not permitted to cross 64-byte boundaries, we only need to save bits 5:2 of the instruction to do this. If the alignment restriction ever gets relaxed, we will then need to save more bits of the address. Decode2 has been extended to handle the R bit of the prefix (in 8LS and MLS forms) and to be able to generate the 34-bit immediate value from the prefix and suffix. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
9 months ago
-- prefix word, PO1
2#000001_00000# to 2#000001_11111# => INSN_prefix,
-- Major opcodes 57 and 61 are SFFS load/store instructions when prefixed
2#111001_00000# to 2#111001_11111# => INSN_op57,
2#111101_00000# to 2#111101_11111# => INSN_op61,
others => INSN_illegal
);
constant row_predecode_rom : predecoder_rom_t := (
-- Major opcode 31
-- Address bits are 0, insn(10:1)
2#0_01000_01010# => INSN_add,
2#0_11000_01010# => INSN_add, -- addo
2#0_00000_01010# => INSN_addc,
2#0_10000_01010# => INSN_addc, -- addco
2#0_00100_01010# => INSN_adde,
2#0_10100_01010# => INSN_adde, -- addeo
2#0_00101_01010# => INSN_addex,
2#0_00010_01010# => INSN_addg6s,
2#0_00111_01010# => INSN_addme,
2#0_10111_01010# => INSN_addme, -- addmeo
2#0_00110_01010# => INSN_addze,
2#0_10110_01010# => INSN_addze, -- addzeo
2#0_00000_11100# => INSN_and,
2#0_00001_11100# => INSN_andc,
2#0_00111_11100# => INSN_bperm,
2#0_00110_11011# => INSN_brh,
2#0_00100_11011# => INSN_brw,
2#0_00101_11011# => INSN_brd,
2#0_01001_11010# => INSN_cbcdtd,
2#0_01000_11010# => INSN_cdtbcd,
2#0_00000_00000# => INSN_cmp,
2#0_01111_11100# => INSN_cmpb,
2#0_00111_00000# => INSN_cmpeqb,
2#0_00001_00000# => INSN_cmpl,
2#0_00110_00000# => INSN_cmprb,
2#0_00001_11010# => INSN_cntlzd,
2#0_00000_11010# => INSN_cntlzw,
2#0_10001_11010# => INSN_cnttzd,
2#0_10000_11010# => INSN_cnttzw,
2#0_10111_10011# => INSN_darn,
2#0_00010_10110# => INSN_dcbf,
2#0_00001_10110# => INSN_dcbst,
2#0_01000_10110# => INSN_dcbt,
2#0_00111_10110# => INSN_dcbtst,
2#0_11111_10110# => INSN_dcbz,
2#0_01100_01001# => INSN_divdeu,
2#0_11100_01001# => INSN_divdeu, -- divdeuo
2#0_01100_01011# => INSN_divweu,
2#0_11100_01011# => INSN_divweu, -- divweuo
2#0_01101_01001# => INSN_divde,
2#0_11101_01001# => INSN_divde, -- divdeo
2#0_01101_01011# => INSN_divwe,
2#0_11101_01011# => INSN_divwe, -- divweo
2#0_01110_01001# => INSN_divdu,
2#0_11110_01001# => INSN_divdu, -- divduo
2#0_01110_01011# => INSN_divwu,
2#0_11110_01011# => INSN_divwu, -- divwuo
2#0_01111_01001# => INSN_divd,
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_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,
2#0_11100_11010# => INSN_extsh,
2#0_11110_11010# => INSN_extsw,
2#0_11011_11010# => INSN_extswsli,
2#0_11011_11011# => INSN_extswsli,
2#0_11110_10110# => INSN_icbi,
2#0_00000_10110# => INSN_icbt,
2#0_00000_01111# => INSN_isel,
2#0_00001_01111# => INSN_isel,
2#0_00010_01111# => INSN_isel,
2#0_00011_01111# => INSN_isel,
2#0_00100_01111# => INSN_isel,
2#0_00101_01111# => INSN_isel,
2#0_00110_01111# => INSN_isel,
2#0_00111_01111# => INSN_isel,
2#0_01000_01111# => INSN_isel,
2#0_01001_01111# => INSN_isel,
2#0_01010_01111# => INSN_isel,
2#0_01011_01111# => INSN_isel,
2#0_01100_01111# => INSN_isel,
2#0_01101_01111# => INSN_isel,
2#0_01110_01111# => INSN_isel,
2#0_01111_01111# => INSN_isel,
2#0_10000_01111# => INSN_isel,
2#0_10001_01111# => INSN_isel,
2#0_10010_01111# => INSN_isel,
2#0_10011_01111# => INSN_isel,
2#0_10100_01111# => INSN_isel,
2#0_10101_01111# => INSN_isel,
2#0_10110_01111# => INSN_isel,
2#0_10111_01111# => INSN_isel,
2#0_11000_01111# => INSN_isel,
2#0_11001_01111# => INSN_isel,
2#0_11010_01111# => INSN_isel,
2#0_11011_01111# => INSN_isel,
2#0_11100_01111# => INSN_isel,
2#0_11101_01111# => INSN_isel,
2#0_11110_01111# => INSN_isel,
2#0_11111_01111# => INSN_isel,
2#0_00001_10100# => INSN_lbarx,
2#0_11010_10101# => INSN_lbzcix,
2#0_00011_10111# => INSN_lbzux,
2#0_00010_10111# => INSN_lbzx,
2#0_00010_10100# => INSN_ldarx,
2#0_10000_10100# => INSN_ldbrx,
2#0_11011_10101# => INSN_ldcix,
2#0_00001_10101# => INSN_ldux,
2#0_00000_10101# => INSN_ldx,
2#0_10010_10111# => INSN_lfdx,
2#0_10011_10111# => INSN_lfdux,
2#0_11010_10111# => INSN_lfiwax,
2#0_11011_10111# => INSN_lfiwzx,
2#0_10000_10111# => INSN_lfsx,
2#0_10001_10111# => INSN_lfsux,
2#0_00011_10100# => INSN_lharx,
2#0_01011_10111# => INSN_lhaux,
2#0_01010_10111# => INSN_lhax,
2#0_11000_10110# => INSN_lhbrx,
2#0_11001_10101# => INSN_lhzcix,
2#0_01001_10111# => INSN_lhzux,
2#0_01000_10111# => INSN_lhzx,
2#0_00000_10100# => INSN_lwarx,
2#0_01011_10101# => INSN_lwaux,
2#0_01010_10101# => INSN_lwax,
2#0_10000_10110# => INSN_lwbrx,
2#0_11000_10101# => INSN_lwzcix,
2#0_00001_10111# => INSN_lwzux,
2#0_00000_10111# => INSN_lwzx,
2#0_10010_00000# => INSN_mcrxrx,
2#0_00000_10011# => INSN_mfcr,
2#0_00010_10011# => INSN_mfmsr,
2#0_01010_10011# => INSN_mfspr,
2#0_01000_01001# => INSN_modud,
2#0_01000_01011# => INSN_moduw,
2#0_11000_01001# => INSN_modsd,
2#0_11000_01011# => INSN_modsw,
2#0_00100_10000# => INSN_mtcrf,
2#0_00100_10010# => INSN_mtmsr,
2#0_00101_10010# => INSN_mtmsrd,
2#0_01110_10011# => INSN_mtspr,
2#0_00010_01001# => INSN_mulhd,
2#0_00000_01001# => INSN_mulhdu,
2#0_00010_01011# => INSN_mulhw,
2#0_00000_01011# => INSN_mulhwu,
-- next 4 have reserved bit set
2#0_10010_01001# => INSN_mulhd,
2#0_10000_01001# => INSN_mulhdu,
2#0_10010_01011# => INSN_mulhw,
2#0_10000_01011# => INSN_mulhwu,
2#0_00111_01001# => INSN_mulld,
2#0_10111_01001# => INSN_mulld, -- mulldo
2#0_00111_01011# => INSN_mullw,
2#0_10111_01011# => INSN_mullw, -- mullwo
2#0_01110_11100# => INSN_nand,
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_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,
2#0_00011_11010# => INSN_popcntb,
2#0_01111_11010# => INSN_popcntd,
2#0_01011_11010# => INSN_popcntw,
2#0_00101_11010# => INSN_prtyd,
2#0_00100_11010# => INSN_prtyw,
2#0_00100_00000# => INSN_setb,
2#0_01100_00000# => INSN_setb, -- setbc
2#0_01101_00000# => INSN_setb, -- setbcr
2#0_01110_00000# => INSN_setb, -- setnbc
2#0_01111_00000# => INSN_setb, -- setnbcr
2#0_01111_10010# => INSN_slbia,
2#0_00000_11011# => INSN_sld,
2#0_00000_11000# => INSN_slw,
2#0_11000_11010# => INSN_srad,
2#0_11001_11010# => INSN_sradi,
2#0_11001_11011# => INSN_sradi,
2#0_11000_11000# => INSN_sraw,
2#0_11001_11000# => INSN_srawi,
2#0_10000_11011# => INSN_srd,
2#0_10000_11000# => INSN_srw,
2#0_11110_10101# => INSN_stbcix,
2#0_10101_10110# => INSN_stbcx,
2#0_00111_10111# => INSN_stbux,
2#0_00110_10111# => INSN_stbx,
2#0_10100_10100# => INSN_stdbrx,
2#0_11111_10101# => INSN_stdcix,
2#0_00110_10110# => INSN_stdcx,
2#0_00101_10101# => INSN_stdux,
2#0_00100_10101# => INSN_stdx,
2#0_10110_10111# => INSN_stfdx,
2#0_10111_10111# => INSN_stfdux,
2#0_11110_10111# => INSN_stfiwx,
2#0_10100_10111# => INSN_stfsx,
2#0_10101_10111# => INSN_stfsux,
2#0_11100_10110# => INSN_sthbrx,
2#0_11101_10101# => INSN_sthcix,
2#0_10110_10110# => INSN_sthcx,
2#0_01101_10111# => INSN_sthux,
2#0_01100_10111# => INSN_sthx,
2#0_10100_10110# => INSN_stwbrx,
2#0_11100_10101# => INSN_stwcix,
2#0_00100_10110# => INSN_stwcx,
2#0_00101_10111# => INSN_stwux,
2#0_00100_10111# => INSN_stwx,
2#0_00001_01000# => INSN_subf,
2#0_10001_01000# => INSN_subf, -- subfo
2#0_00000_01000# => INSN_subfc,
2#0_10000_01000# => INSN_subfc, -- subfco
2#0_00100_01000# => INSN_subfe,
2#0_10100_01000# => INSN_subfe, -- subfeo
2#0_00111_01000# => INSN_subfme,
2#0_10111_01000# => INSN_subfme, -- subfmeo
2#0_00110_01000# => INSN_subfze,
2#0_10110_01000# => INSN_subfze, -- subfzeo
2#0_10010_10110# => INSN_sync,
2#0_00010_00100# => INSN_td,
2#0_00000_00100# => INSN_tw,
2#0_01001_10010# => INSN_tlbie,
2#0_01000_10010# => INSN_tlbiel,
2#0_10001_10110# => INSN_tlbsync,
2#0_00000_11110# => INSN_wait,
2#0_01001_11100# => INSN_xor,
-- Major opcode 19
-- Columns with insn(4) = '1' are all illegal and not mapped here; to
-- fit into 2048 entries, the columns are remapped so that 16-24 are
-- stored here as 8-15; in other words the address bits are
-- 1, insn(10..6), 1, insn(5), insn(3..1)
-- Columns 16-17 here are opcode 19 columns 0-1
-- Columns 24-31 here are opcode 19 columns 16-23
2#1_10000_11000# => INSN_bcctr,
2#1_00000_11000# => INSN_bclr,
2#1_10001_11000# => INSN_bctar,
2#1_01000_10001# => INSN_crand,
2#1_00100_10001# => INSN_crandc,
2#1_01001_10001# => INSN_creqv,
2#1_00111_10001# => INSN_crnand,
2#1_00001_10001# => INSN_crnor,
2#1_01110_10001# => INSN_cror,
2#1_01101_10001# => INSN_crorc,
2#1_00110_10001# => INSN_crxor,
2#1_00100_11110# => INSN_isync,
2#1_00000_10000# => INSN_mcrf,
2#1_00000_11010# => INSN_rfid,
-- Major opcode 59
-- Address bits are 1, insn(10..6), 1, 0, insn(3..1)
-- Only column 14 is valid here; columns 16-31 are handled in the major table
-- Column 14 is mapped to column 22.
-- Columns 20-23 here are opcode 59 columns 12-15
2#1_11010_10110# => INSN_fcfids,
2#1_11110_10110# => INSN_fcfidus,
-- Major opcode 63
-- Columns 0-15 are mapped here; columns 16-31 are in the major table.
-- Address bits are 1, insn(10:6), 0, insn(4:1)
-- Columns 0-15 here are opcode 63 columns 0-15
2#1_00000_00000# => INSN_fcmpu,
2#1_00001_00000# => INSN_fcmpo,
2#1_00010_00000# => INSN_mcrfs,
2#1_00100_00000# => INSN_ftdiv,
2#1_00101_00000# => INSN_ftsqrt,
2#1_00001_00110# => INSN_mtfsb,
2#1_00010_00110# => INSN_mtfsb,
2#1_00100_00110# => INSN_mtfsfi,
2#1_11010_00110# => INSN_fmrgow,
2#1_11110_00110# => INSN_fmrgew,
2#1_10010_00111# => INSN_mffs,
2#1_10110_00111# => INSN_mtfsf,
2#1_00000_01000# => INSN_fcpsgn,
2#1_00001_01000# => INSN_fneg,
2#1_00010_01000# => INSN_fmr,
2#1_00100_01000# => INSN_fnabs,
2#1_01000_01000# => INSN_fabs,
2#1_01100_01000# => INSN_frin,
2#1_01101_01000# => INSN_friz,
2#1_01110_01000# => INSN_frip,
2#1_01111_01000# => INSN_frim,
2#1_00000_01100# => INSN_frsp,
2#1_00000_01110# => INSN_fctiw,
2#1_00100_01110# => INSN_fctiwu,
2#1_11001_01110# => INSN_fctid,
2#1_11010_01110# => INSN_fcfid,
2#1_11101_01110# => INSN_fctidu,
2#1_11110_01110# => INSN_fcfidu,
2#1_00000_01111# => INSN_fctiwz,
2#1_00100_01111# => INSN_fctiwuz,
2#1_11001_01111# => INSN_fctidz,
2#1_11101_01111# => INSN_fctiduz,
others => INSN_illegal
);
constant IOUT_LEN : natural := ICODE_LEN + IMAGE_LEN;
type predec_t is record
image : std_ulogic_vector(31 downto 0);
maj_predecode : unsigned(ICODE_LEN - 1 downto 0);
row_predecode : unsigned(ICODE_LEN - 1 downto 0);
end record;
subtype index_t is integer range 0 to WIDTH-1;
type predec_array is array(index_t) of predec_t;
signal pred : predec_array;
signal valid : std_ulogic;
begin
predecode_0: process(clk)
variable majaddr : std_ulogic_vector(10 downto 0);
variable rowaddr : std_ulogic_vector(10 downto 0);
variable iword : std_ulogic_vector(31 downto 0);
variable majcode : insn_code;
variable rowcode : insn_code;
begin
if rising_edge(clk) then
valid <= valid_in;
for i in index_t loop
iword := insns_in(i * 32 + 31 downto i * 32);
pred(i).image <= iword;
if is_X(iword) then
pred(i).maj_predecode <= (others => 'X');
pred(i).row_predecode <= (others => 'X');
else
majaddr := iword(31 downto 26) & iword(4 downto 0);
-- row_predecode_rom is used for op 19, 31, 59, 63
-- addr bit 10 is 0 for op 31, 1 for 19, 59, 63
rowaddr(10) := iword(31) or not iword(29);
rowaddr(9 downto 5) := iword(10 downto 6);
if iword(28) = '0' then
-- op 19 and op 59
rowaddr(4 downto 3) := '1' & iword(5);
else
-- op 31 and 63; for 63 we only use this when iword(5) = '0'
rowaddr(4 downto 3) := iword(5 downto 4);
end if;
rowaddr(2 downto 0) := iword(3 downto 1);
majcode := major_predecode_rom(to_integer(unsigned(majaddr)));
pred(i).maj_predecode <= to_unsigned(insn_code'pos(majcode), ICODE_LEN);
rowcode := row_predecode_rom(to_integer(unsigned(rowaddr)));
pred(i).row_predecode <= to_unsigned(insn_code'pos(rowcode), ICODE_LEN);
end if;
end loop;
end if;
end process;
predecode_1: process(all)
variable iword : std_ulogic_vector(31 downto 0);
variable use_row : std_ulogic;
variable illegal : std_ulogic;
variable ici : std_ulogic_vector(IOUT_LEN - 1 downto 0);
variable icode : unsigned(ICODE_LEN - 1 downto 0);
begin
for i in index_t loop
iword := pred(i).image;
icode := pred(i).maj_predecode;
use_row := '0';
illegal := '0';
case iword(31 downto 26) is
when "000100" => -- 4
-- major opcode 4, mostly VMX/VSX stuff but also some integer ops (madd*)
illegal := not iword(5);
when "010011" => -- 19
-- 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
-- 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.
illegal := iword(4);
use_row := iword(5) or (not iword(3) and not iword(2));
when "011000" => -- 24
-- ori, special-case the standard NOP
if std_match(iword, "01100000000000000000000000000000") then
icode := to_unsigned(insn_code'pos(INSN_nop), ICODE_LEN);
end if;
when "011111" => -- 31
-- major opcode 31, lots of things
-- Use the first half of the row table for all columns
use_row := '1';
when "111011" => -- 59
-- floating point operations, mostly single-precision
-- 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.
illegal := not iword(5) and (not iword(4) or not iword(3));
use_row := not iword(5);
when "111111" => -- 63
-- 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.
use_row := not iword(5);
when others =>
end case;
if use_row = '1' then
icode := pred(i).row_predecode;
end if;
-- Mark FP instructions as illegal if we don't have an FPU
if not HAS_FPU and not is_X(icode) and
to_integer(icode) >= insn_code'pos(INSN_first_frs) then
illegal := '1';
end if;
ici(31 downto 0) := iword;
ici(IOUT_LEN - 1 downto 32) := (others => '0');
if valid = '0' or illegal = '1' or is_X(icode) or
icode = to_unsigned(insn_code'pos(INSN_illegal), ICODE_LEN) then
-- Since an insn_code currently fits in 9 bits, use just
-- the most significant bit of ici to indicate illegal insns.
ici(IOUT_LEN - 1) := '1';
else
ici(IOUT_LEN - 1 downto IMAGE_LEN) := std_ulogic_vector(icode);
end if;
icodes_out(i * IOUT_LEN + IOUT_LEN - 1 downto i * IOUT_LEN) <= ici;
end loop;
end process;
end architecture behaviour;