mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-13 15:18:09 +00:00
This changes the decoding of major opcode 19 from using the ppc_insn_t index to using bits of the instruction word directly. Opcode 19 has a 10-bit minor opcode field (bits 10..1) but the space is sparsely filled. Therefore we index a table of single-bit entries with the 10-bit minor opcode to filter out the illegal minor opcodes, and index a table using just 3 bits -- 5, 3 and 2 -- of the instruction to get the decode entry. This groups together all the instructions in 4 columns of the opcode map as a single entry. That means that mcrf and all the CR logical ops get grouped together, and bcctr, bclr and bctar get grouped together. At present the CR logical ops are not implemented, so their grouping has no impact. The code for bclr and bcctr in execute1 is now common, using a single op, and it now determines the branch address by looking at bit 10 of the instruction word at execute time. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
387 lines
13 KiB
VHDL
387 lines
13 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.decode_types.all;
|
|
use work.common.all;
|
|
use work.helpers.all;
|
|
use work.crhelpers.all;
|
|
use work.insn_helpers.all;
|
|
use work.ppc_fx_insns.all;
|
|
|
|
entity execute1 is
|
|
generic (
|
|
SIM : boolean := false
|
|
);
|
|
port (
|
|
clk : in std_logic;
|
|
|
|
-- asynchronous
|
|
flush_out : out std_ulogic;
|
|
|
|
e_in : in Decode2ToExecute1Type;
|
|
|
|
-- asynchronous
|
|
f_out : out Execute1ToFetch1Type;
|
|
|
|
e_out : out Execute1ToExecute2Type;
|
|
|
|
terminate_out : out std_ulogic
|
|
);
|
|
end entity execute1;
|
|
|
|
architecture behaviour of execute1 is
|
|
type reg_type is record
|
|
--f : Execute1ToFetch1Type;
|
|
e : Execute1ToExecute2Type;
|
|
end record;
|
|
|
|
signal r, rin : reg_type;
|
|
|
|
signal ctrl: ctrl_t := (carry => '0', others => (others => '0'));
|
|
signal ctrl_tmp: ctrl_t := (carry => '0', others => (others => '0'));
|
|
begin
|
|
execute1_0: process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
r <= rin;
|
|
ctrl <= ctrl_tmp;
|
|
end if;
|
|
end process;
|
|
|
|
execute1_1: process(all)
|
|
variable v : reg_type;
|
|
variable result : std_ulogic_vector(63 downto 0);
|
|
variable newcrf : std_ulogic_vector(3 downto 0);
|
|
variable result_with_carry : std_ulogic_vector(64 downto 0);
|
|
variable result_en : integer;
|
|
variable crnum : integer;
|
|
variable scrnum : integer;
|
|
variable lo, hi : integer;
|
|
begin
|
|
result := (others => '0');
|
|
result_with_carry := (others => '0');
|
|
result_en := 0;
|
|
|
|
v := r;
|
|
v.e := Execute1ToExecute2Init;
|
|
--v.f := Execute1ToFetch1TypeInit;
|
|
|
|
ctrl_tmp <= ctrl;
|
|
-- FIXME: run at 512MHz not core freq
|
|
ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1);
|
|
|
|
terminate_out <= '0';
|
|
f_out <= Execute1ToFetch1TypeInit;
|
|
|
|
if e_in.valid = '1' then
|
|
|
|
v.e.valid := '1';
|
|
v.e.write_reg := e_in.write_reg;
|
|
|
|
case_0: case e_in.insn_type is
|
|
|
|
when OP_ILLEGAL =>
|
|
terminate_out <= '1';
|
|
report "illegal";
|
|
when OP_NOP =>
|
|
-- Do nothing
|
|
when OP_ADD =>
|
|
result := ppc_add(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_ADDE =>
|
|
result_with_carry := ppc_adde(e_in.read_data1, e_in.read_data2, ctrl.carry and e_in.input_carry);
|
|
result := result_with_carry(63 downto 0);
|
|
ctrl_tmp.carry <= result_with_carry(64) and e_in.output_carry;
|
|
result_en := 1;
|
|
when OP_AND =>
|
|
result := ppc_and(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_ANDC =>
|
|
result := ppc_andc(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_B =>
|
|
f_out.redirect <= '1';
|
|
if (insn_aa(e_in.insn)) then
|
|
f_out.redirect_nia <= std_ulogic_vector(signed(e_in.read_data2));
|
|
else
|
|
f_out.redirect_nia <= std_ulogic_vector(signed(e_in.nia) + signed(e_in.read_data2));
|
|
end if;
|
|
when OP_BC =>
|
|
if e_in.const1(4-2) = '0' then
|
|
ctrl_tmp.ctr <= std_ulogic_vector(unsigned(ctrl.ctr) - 1);
|
|
end if;
|
|
if ppc_bc_taken(e_in.const1(4 downto 0), e_in.const2(4 downto 0), e_in.cr, ctrl.ctr) = 1 then
|
|
f_out.redirect <= '1';
|
|
if (insn_aa(e_in.insn)) then
|
|
f_out.redirect_nia <= std_ulogic_vector(signed(e_in.read_data2));
|
|
else
|
|
f_out.redirect_nia <= std_ulogic_vector(signed(e_in.nia) + signed(e_in.read_data2));
|
|
end if;
|
|
end if;
|
|
when OP_BCREG =>
|
|
-- bits 10 and 6 distinguish between bclr, bcctr and bctar
|
|
if e_in.const1(4-2) = '0' and e_in.insn(10) = '0' then
|
|
ctrl_tmp.ctr <= std_ulogic_vector(unsigned(ctrl.ctr) - 1);
|
|
end if;
|
|
if ppc_bc_taken(e_in.const1(4 downto 0), e_in.const2(4 downto 0), e_in.cr, ctrl.ctr) = 1 then
|
|
f_out.redirect <= '1';
|
|
if e_in.insn(10) = '0' then
|
|
f_out.redirect_nia <= ctrl.lr(63 downto 2) & "00";
|
|
else
|
|
f_out.redirect_nia <= ctrl.ctr(63 downto 2) & "00";
|
|
end if;
|
|
end if;
|
|
when OP_CMPB =>
|
|
result := ppc_cmpb(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_CMP =>
|
|
v.e.write_cr_enable := '1';
|
|
crnum := to_integer(unsigned(e_in.const1(2 downto 0)));
|
|
v.e.write_cr_mask := num_to_fxm(crnum);
|
|
for i in 0 to 7 loop
|
|
lo := i*4;
|
|
hi := lo + 3;
|
|
v.e.write_cr_data(hi downto lo) := ppc_cmp(e_in.const2(0), e_in.read_data1, e_in.read_data2);
|
|
end loop;
|
|
when OP_CMPL =>
|
|
v.e.write_cr_enable := '1';
|
|
crnum := to_integer(unsigned(e_in.const1(2 downto 0)));
|
|
v.e.write_cr_mask := num_to_fxm(crnum);
|
|
for i in 0 to 7 loop
|
|
lo := i*4;
|
|
hi := lo + 3;
|
|
v.e.write_cr_data(hi downto lo) := ppc_cmpl(e_in.const2(0), e_in.read_data1, e_in.read_data2);
|
|
end loop;
|
|
when OP_CNTLZW =>
|
|
result := ppc_cntlzw(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_CNTTZW =>
|
|
result := ppc_cnttzw(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_CNTLZD =>
|
|
result := ppc_cntlzd(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_CNTTZD =>
|
|
result := ppc_cnttzd(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_EXTSB =>
|
|
result := ppc_extsb(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_EXTSH =>
|
|
result := ppc_extsh(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_EXTSW =>
|
|
result := ppc_extsw(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_EQV =>
|
|
result := ppc_eqv(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_ISEL =>
|
|
crnum := to_integer(unsigned(e_in.const1));
|
|
if e_in.cr(31-crnum) = '1' then
|
|
result := e_in.read_data1;
|
|
else
|
|
result := e_in.read_data2;
|
|
end if;
|
|
result_en := 1;
|
|
when OP_MCRF =>
|
|
v.e.write_cr_enable := '1';
|
|
crnum := to_integer(unsigned(e_in.const1(2 downto 0)));
|
|
scrnum := to_integer(unsigned(e_in.const2(2 downto 0)));
|
|
v.e.write_cr_mask := num_to_fxm(crnum);
|
|
for i in 0 to 7 loop
|
|
lo := (7-i)*4;
|
|
hi := lo + 3;
|
|
if i = scrnum then
|
|
newcrf := e_in.cr(hi downto lo);
|
|
end if;
|
|
end loop;
|
|
for i in 0 to 7 loop
|
|
lo := i*4;
|
|
hi := lo + 3;
|
|
v.e.write_cr_data(hi downto lo) := newcrf;
|
|
end loop;
|
|
when OP_MFSPR =>
|
|
if std_match(e_in.insn(20 downto 11), "0100100000") then
|
|
result := ctrl.ctr;
|
|
result_en := 1;
|
|
elsif std_match(e_in.insn(20 downto 11), "0100000000") then
|
|
result := ctrl.lr;
|
|
result_en := 1;
|
|
elsif std_match(e_in.insn(20 downto 11), "0110001000") then
|
|
result := ctrl.tb;
|
|
result_en := 1;
|
|
end if;
|
|
when OP_MFCR =>
|
|
result := x"00000000" & e_in.cr;
|
|
result_en := 1;
|
|
when OP_MFOCRF =>
|
|
crnum := fxm_to_num(e_in.const1(7 downto 0));
|
|
result := (others => '0');
|
|
for i in 0 to 7 loop
|
|
lo := (7-i)*4;
|
|
hi := lo + 3;
|
|
if crnum = i then
|
|
result(hi downto lo) := e_in.cr(hi downto lo);
|
|
end if;
|
|
end loop;
|
|
result_en := 1;
|
|
when OP_MTCRF =>
|
|
v.e.write_cr_enable := '1';
|
|
v.e.write_cr_mask := e_in.const1(7 downto 0);
|
|
v.e.write_cr_data := e_in.read_data1(31 downto 0);
|
|
when OP_MTOCRF =>
|
|
v.e.write_cr_enable := '1';
|
|
-- We require one hot priority encoding here
|
|
crnum := fxm_to_num(e_in.const1(7 downto 0));
|
|
v.e.write_cr_mask := num_to_fxm(crnum);
|
|
v.e.write_cr_data := e_in.read_data1(31 downto 0);
|
|
when OP_MTSPR =>
|
|
if std_match(e_in.insn(20 downto 11), "0100100000") then
|
|
ctrl_tmp.ctr <= e_in.read_data1;
|
|
elsif std_match(e_in.insn(20 downto 11), "0100000000") then
|
|
ctrl_tmp.lr <= e_in.read_data1;
|
|
end if;
|
|
when OP_NAND =>
|
|
result := ppc_nand(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_NEG =>
|
|
result := ppc_neg(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_NOR =>
|
|
result := ppc_nor(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_OR =>
|
|
result := ppc_or(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_ORC =>
|
|
result := ppc_orc(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_POPCNTB =>
|
|
result := ppc_popcntb(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_POPCNTW =>
|
|
result := ppc_popcntw(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_POPCNTD =>
|
|
result := ppc_popcntd(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_PRTYD =>
|
|
result := ppc_prtyd(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_PRTYW =>
|
|
result := ppc_prtyw(e_in.read_data1);
|
|
result_en := 1;
|
|
when OP_RLDCL =>
|
|
result := ppc_rldcl(e_in.read_data1, e_in.read_data2, e_in.const2(5 downto 0));
|
|
result_en := 1;
|
|
when OP_RLDCR =>
|
|
result := ppc_rldcr(e_in.read_data1, e_in.read_data2, e_in.const2(5 downto 0));
|
|
result_en := 1;
|
|
when OP_RLDICL =>
|
|
result := ppc_rldicl(e_in.read_data1, e_in.const1(5 downto 0), e_in.const2(5 downto 0));
|
|
result_en := 1;
|
|
when OP_RLDICR =>
|
|
result := ppc_rldicr(e_in.read_data1, e_in.const1(5 downto 0), e_in.const2(5 downto 0));
|
|
result_en := 1;
|
|
when OP_RLWNM =>
|
|
result := ppc_rlwnm(e_in.read_data1, e_in.read_data2, e_in.const2(4 downto 0), e_in.const3(4 downto 0));
|
|
result_en := 1;
|
|
when OP_RLWINM =>
|
|
result := ppc_rlwinm(e_in.read_data1, e_in.const1(4 downto 0), e_in.const2(4 downto 0), e_in.const3(4 downto 0));
|
|
result_en := 1;
|
|
when OP_RLDIC =>
|
|
result := ppc_rldic(e_in.read_data1, e_in.const1(5 downto 0), e_in.const2(5 downto 0));
|
|
result_en := 1;
|
|
when OP_RLDIMI =>
|
|
result := ppc_rldimi(e_in.read_data1, e_in.read_data2, e_in.const1(5 downto 0), e_in.const2(5 downto 0));
|
|
result_en := 1;
|
|
when OP_RLWIMI =>
|
|
result := ppc_rlwimi(e_in.read_data1, e_in.read_data2, e_in.const1(4 downto 0), e_in.const2(4 downto 0), e_in.const3(4 downto 0));
|
|
result_en := 1;
|
|
when OP_SLD =>
|
|
result := ppc_sld(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_SLW =>
|
|
result := ppc_slw(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_SRAW =>
|
|
result_with_carry := ppc_sraw(e_in.read_data1, e_in.read_data2);
|
|
result := result_with_carry(63 downto 0);
|
|
ctrl_tmp.carry <= result_with_carry(64);
|
|
result_en := 1;
|
|
when OP_SRAWI =>
|
|
result_with_carry := ppc_srawi(e_in.read_data1, e_in.const1(5 downto 0));
|
|
result := result_with_carry(63 downto 0);
|
|
ctrl_tmp.carry <= result_with_carry(64);
|
|
result_en := 1;
|
|
when OP_SRAD =>
|
|
result_with_carry := ppc_srad(e_in.read_data1, e_in.read_data2);
|
|
result := result_with_carry(63 downto 0);
|
|
ctrl_tmp.carry <= result_with_carry(64);
|
|
result_en := 1;
|
|
when OP_SRADI =>
|
|
result_with_carry := ppc_sradi(e_in.read_data1, e_in.const1(5 downto 0));
|
|
result := result_with_carry(63 downto 0);
|
|
ctrl_tmp.carry <= result_with_carry(64);
|
|
result_en := 1;
|
|
when OP_SRD =>
|
|
result := ppc_srd(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_SRW =>
|
|
result := ppc_srw(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_SUBF =>
|
|
result := ppc_subf(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
when OP_SUBFE =>
|
|
result_with_carry := ppc_subfe(e_in.read_data1, e_in.read_data2, ctrl.carry or not(e_in.input_carry));
|
|
result := result_with_carry(63 downto 0);
|
|
ctrl_tmp.carry <= result_with_carry(64) and e_in.output_carry;
|
|
result_en := 1;
|
|
when OP_XOR =>
|
|
result := ppc_xor(e_in.read_data1, e_in.read_data2);
|
|
result_en := 1;
|
|
|
|
when OP_SIM_CONFIG =>
|
|
-- bit 0 was used to select the microwatt console, which
|
|
-- we no longer support.
|
|
if SIM = true then
|
|
result := x"0000000000000000";
|
|
else
|
|
result := x"0000000000000000";
|
|
end if;
|
|
result_en := 1;
|
|
|
|
when OP_TDI =>
|
|
-- Keep our test cases happy for now, ignore trap instructions
|
|
report "OP_TDI FIXME";
|
|
|
|
when others =>
|
|
terminate_out <= '1';
|
|
report "illegal";
|
|
end case;
|
|
|
|
if e_in.lr = '1' then
|
|
ctrl_tmp.lr <= std_ulogic_vector(unsigned(e_in.nia) + 4);
|
|
end if;
|
|
|
|
if result_en = 1 then
|
|
v.e.write_data := result;
|
|
v.e.write_enable := '1';
|
|
v.e.rc := e_in.rc;
|
|
end if;
|
|
end if;
|
|
|
|
-- Update registers
|
|
rin <= v;
|
|
|
|
-- update outputs
|
|
--f_out <= r.f;
|
|
e_out <= r.e;
|
|
flush_out <= f_out.redirect;
|
|
end process;
|
|
end architecture behaviour;
|