rc: std_ulogic;
oe: std_ulogic;
invert_a: std_ulogic;
+ addm1 : std_ulogic;
invert_out: std_ulogic;
input_carry: carry_in_t;
output_carry: std_ulogic;
update : std_ulogic; -- is this an update instruction?
reserve : std_ulogic; -- set for larx/stcx
br_pred : std_ulogic;
+ result_sel : std_ulogic_vector(2 downto 0); -- select source of result
+ sub_select : std_ulogic_vector(2 downto 0); -- sub-result selection
repeat : std_ulogic; -- set if instruction is cracked into two ops
second : std_ulogic; -- set if this is the second op
end record;
constant Decode2ToExecute1Init : Decode2ToExecute1Type :=
(valid => '0', unit => NONE, fac => NONE, insn_type => OP_ILLEGAL,
bypass_data1 => '0', bypass_data2 => '0', bypass_data3 => '0',
- bypass_cr => '0', lr => '0', rc => '0', oe => '0', invert_a => '0',
+ bypass_cr => '0', lr => '0', rc => '0', oe => '0', invert_a => '0', addm1 => '0',
invert_out => '0', input_carry => ZERO, output_carry => '0', input_cr => '0', output_cr => '0',
is_32bit => '0', is_signed => '0', xerc => xerc_init, reserve => '0', br_pred => '0',
byte_reverse => '0', sign_extend => '0', update => '0', nia => (others => '0'),
read_data1 => (others => '0'), read_data2 => (others => '0'), read_data3 => (others => '0'),
cr => (others => '0'), insn => (others => '0'), data_len => (others => '0'),
+ result_sel => "000", sub_select => "000",
repeat => '0', second => '0', others => (others => '0'));
type MultiplyInputType is record
prev_op : insn_type_t;
lr_update : std_ulogic;
next_lr : std_ulogic_vector(63 downto 0);
+ resmux : std_ulogic_vector(2 downto 0);
+ submux : std_ulogic_vector(2 downto 0);
mul_in_progress : std_ulogic;
mul_finish : std_ulogic;
div_in_progress : std_ulogic;
signal rotator_carry: std_ulogic;
signal logical_result: std_ulogic_vector(63 downto 0);
signal countzero_result: std_ulogic_vector(63 downto 0);
+ signal alu_result: std_ulogic_vector(63 downto 0);
+ signal adder_result: std_ulogic_vector(63 downto 0);
+ signal misc_result: std_ulogic_vector(63 downto 0);
+ signal muldiv_result: std_ulogic_vector(63 downto 0);
+ signal spr_result: std_ulogic_vector(63 downto 0);
+ signal result_mux_sel: std_ulogic_vector(2 downto 0);
+ signal sub_mux_sel: std_ulogic_vector(2 downto 0);
-- multiply signals
signal x_to_multiply: MultiplyInputType;
terminate_out <= r.terminate;
+ -- Result mux
+ result_mux_sel <= e_in.result_sel when r.busy = '0' else r.resmux;
+ sub_mux_sel <= e_in.sub_select when r.busy = '0' else r.submux;
+ with result_mux_sel select alu_result <=
+ adder_result when "000",
+ logical_result when "001",
+ rotator_result when "010",
+ muldiv_result when "011",
+ countzero_result when "100",
+ spr_result when "101",
+ misc_result when others;
+
execute1_0: process(clk)
begin
if rising_edge(clk) then
execute1_1: process(all)
variable v : reg_type;
variable a_inv : std_ulogic_vector(63 downto 0);
- variable result : std_ulogic_vector(63 downto 0);
+ variable b_or_m1 : std_ulogic_vector(63 downto 0);
+ variable addg6s : std_ulogic_vector(63 downto 0);
variable newcrf : std_ulogic_vector(3 downto 0);
variable sum_with_carry : std_ulogic_vector(64 downto 0);
variable result_en : std_ulogic;
variable spr_val : std_ulogic_vector(63 downto 0);
variable addend : std_ulogic_vector(127 downto 0);
variable do_trace : std_ulogic;
+ variable hold_wr_data : std_ulogic;
variable f : Execute1ToFetch1Type;
variable fv : Execute1ToFPUType;
begin
- result := (others => '0');
sum_with_carry := (others => '0');
result_en := '0';
newcrf := (others => '0');
is_branch := '0';
taken_branch := '0';
abs_branch := '0';
+ hold_wr_data := '0';
v := r;
v.e := Execute1ToWritebackInit;
v.cntz_in_progress := '0';
v.mul_finish := '0';
+ misc_result <= (others => '0');
+ spr_result <= (others => '0');
+ spr_val := (others => '0');
+
-- Main adder
if e_in.invert_a = '0' then
a_inv := a_in;
else
a_inv := not a_in;
end if;
- sum_with_carry := ppc_adde(a_inv, b_in,
+ if e_in.addm1 = '0' then
+ b_or_m1 := b_in;
+ else
+ b_or_m1 := (others => '1');
+ end if;
+ sum_with_carry := ppc_adde(a_inv, b_or_m1,
decode_input_carry(e_in.input_carry, v.e.xerc));
+ adder_result <= sum_with_carry(63 downto 0);
-- signals to multiply and divide units
sign1 := '0';
abs2 := - signed(b_in);
end if;
+ -- Interface to multiply and divide units
x_to_multiply <= MultiplyInputInit;
x_to_multiply.is_32bit <= e_in.is_32bit;
x_to_divider.divisor <= x"00000000" & std_ulogic_vector(abs2(31 downto 0));
end if;
+ case sub_mux_sel(1 downto 0) is
+ when "00" =>
+ muldiv_result <= multiply_to_x.result(63 downto 0);
+ when "01" =>
+ muldiv_result <= multiply_to_x.result(127 downto 64);
+ when "10" =>
+ muldiv_result <= multiply_to_x.result(63 downto 32) &
+ multiply_to_x.result(63 downto 32);
+ when others =>
+ muldiv_result <= divider_to_x.write_reg_data;
+ end case;
+
ctrl_tmp <= ctrl;
-- FIXME: run at 512MHz not core freq
ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1);
v.slow_op_rc := e_in.rc;
v.slow_op_oe := e_in.oe;
v.slow_op_xerc := v.e.xerc;
+ v.resmux := e_in.result_sel;
+ v.submux := e_in.sub_select;
case_0: case e_in.insn_type is
when OP_NOP | OP_DCBF | OP_DCBST | OP_DCBT | OP_DCBTST | OP_ICBT =>
-- Do nothing
when OP_ADD | OP_CMP | OP_TRAP =>
- result := sum_with_carry(63 downto 0);
- carry_32 := result(32) xor a_inv(32) xor b_in(32);
+ carry_32 := sum_with_carry(32) xor a_inv(32) xor b_in(32);
carry_64 := sum_with_carry(64);
if e_in.insn_type = OP_ADD then
if e_in.output_carry = '1' then
end if;
end if;
when OP_ADDG6S =>
- result := (others => '0');
+ addg6s := (others => '0');
for i in 0 to 14 loop
lo := i * 4;
hi := (i + 1) * 4;
if (a_in(hi) xor b_in(hi) xor sum_with_carry(hi)) = '0' then
- result(lo + 3 downto lo) := "0110";
+ addg6s(lo + 3 downto lo) := "0110";
end if;
end loop;
if sum_with_carry(64) = '0' then
- result(63 downto 60) := "0110";
+ addg6s(63 downto 60) := "0110";
end if;
+ misc_result <= addg6s;
result_en := '1';
when OP_CMPRB =>
newcrf := ppc_cmprb(a_in, b_in, insn_l(e_in.insn));
newcrf & newcrf & newcrf & newcrf;
when OP_AND | OP_OR | OP_XOR | OP_POPCNT | OP_PRTY | OP_CMPB | OP_EXTS |
OP_BPERM | OP_BCD =>
- result := logical_result;
result_en := '1';
when OP_B =>
is_branch := '1';
end if;
when OP_BC =>
-- read_data1 is CTR
+ v.e.write_reg := fast_spr_num(SPR_CTR);
bo := insn_bo(e_in.insn);
bi := insn_bi(e_in.insn);
if bo(4-2) = '0' then
- result := std_ulogic_vector(unsigned(a_in) - 1);
result_en := '1';
- v.e.write_reg := fast_spr_num(SPR_CTR);
end if;
is_branch := '1';
taken_branch := ppc_bc_taken(bo, bi, cr_in, a_in);
when OP_BCREG =>
-- read_data1 is CTR
-- read_data2 is target register (CTR, LR or TAR)
+ v.e.write_reg := fast_spr_num(SPR_CTR);
bo := insn_bo(e_in.insn);
bi := insn_bi(e_in.insn);
if bo(4-2) = '0' and e_in.insn(10) = '0' then
- result := std_ulogic_vector(unsigned(a_in) - 1);
result_en := '1';
- v.e.write_reg := fast_spr_num(SPR_CTR);
end if;
is_branch := '1';
taken_branch := ppc_bc_taken(bo, bi, cr_in, a_in);
when OP_ISEL =>
crbit := to_integer(unsigned(insn_bc(e_in.insn)));
if cr_in(31-crbit) = '1' then
- result := a_in;
+ misc_result <= a_in;
else
- result := b_in;
+ misc_result <= b_in;
end if;
result_en := '1';
when OP_CROP =>
if random_err = '0' then
case e_in.insn(17 downto 16) is
when "00" =>
- result := x"00000000" & random_cond(31 downto 0);
+ misc_result <= x"00000000" & random_cond(31 downto 0);
when "10" =>
- result := random_raw;
+ misc_result <= random_raw;
when others =>
- result := random_cond;
+ misc_result <= random_cond;
end case;
else
- result := (others => '1');
+ misc_result <= (others => '1');
end if;
result_en := '1';
when OP_MFMSR =>
- result := ctrl.msr;
+ misc_result <= ctrl.msr;
result_en := '1';
when OP_MFSPR =>
report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
"=" & to_hstring(a_in);
result_en := '1';
if is_fast_spr(e_in.read_reg1) then
- result := a_in;
- if decode_spr_num(e_in.insn) = SPR_XER then
+ spr_val := a_in;
+ if decode_spr_num(e_in.insn) = SPR_XER then
-- bits 0:31 and 35:43 are treated as reserved and return 0s when read using mfxer
- result(63 downto 32) := (others => '0');
- result(63-32) := v.e.xerc.so;
- result(63-33) := v.e.xerc.ov;
- result(63-34) := v.e.xerc.ca;
- result(63-35 downto 63-43) := "000000000";
- result(63-44) := v.e.xerc.ov32;
- result(63-45) := v.e.xerc.ca32;
- end if;
+ spr_val(63 downto 32) := (others => '0');
+ spr_val(63-32) := v.e.xerc.so;
+ spr_val(63-33) := v.e.xerc.ov;
+ spr_val(63-34) := v.e.xerc.ca;
+ spr_val(63-35 downto 63-43) := "000000000";
+ spr_val(63-44) := v.e.xerc.ov32;
+ spr_val(63-45) := v.e.xerc.ca32;
+ end if;
else
spr_val := c_in;
- case decode_spr_num(e_in.insn) is
+ case decode_spr_num(e_in.insn) is
when SPR_TB =>
spr_val := ctrl.tb;
when SPR_TBU =>
if ctrl.msr(MSR_PR) = '1' then
illegal := '1';
end if;
- end case;
- result := spr_val;
- end if;
+ end case;
+ end if;
+ spr_result <= spr_val;
+
when OP_MFCR =>
if e_in.insn(20) = '0' then
-- mfcr
- result := x"00000000" & cr_in;
+ misc_result <= x"00000000" & cr_in;
else
-- mfocrf
crnum := fxm_to_num(insn_fxm(e_in.insn));
- result := (others => '0');
+ misc_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) := cr_in(hi downto lo);
+ misc_result(hi downto lo) <= cr_in(hi downto lo);
end if;
end loop;
end if;
report "MTSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
"=" & to_hstring(c_in);
if is_fast_spr(e_in.write_reg) then
- result := c_in;
result_en := '1';
if decode_spr_num(e_in.insn) = SPR_XER then
v.e.xerc.so := c_in(63-32);
end case;
end if;
when OP_RLC | OP_RLCL | OP_RLCR | OP_SHL | OP_SHR | OP_EXTSWSLI =>
- result := rotator_result;
if e_in.output_carry = '1' then
set_carry(v.e, rotator_carry, rotator_carry);
end if;
when OP_SETB =>
bfa := insn_bfa(e_in.insn);
crbit := to_integer(unsigned(bfa)) * 4;
- result := (others => '0');
+ misc_result <= (others => '0');
if cr_in(31 - crbit) = '1' then
- result := (others => '1');
+ misc_result <= (others => '1');
elsif cr_in(30 - crbit) = '1' then
- result(0) := '1';
+ misc_result(0) <= '1';
end if;
when OP_ISYNC =>
v.e.valid := '1';
-- Keep r.e.write_data unchanged next cycle in case it is needed
-- for a forwarded result (e.g. for CTR).
- result := r.e.write_data;
+ hold_wr_data := '1';
elsif r.cntz_in_progress = '1' then
-- cnt[lt]z always takes two cycles
- result := countzero_result;
result_en := '1';
v.e.write_reg := gpr_to_gspr(r.slow_op_dest);
v.e.rc := r.slow_op_rc;
(r.div_in_progress = '1' and divider_to_x.valid = '1') then
if r.mul_in_progress = '1' then
overflow := '0';
- case r.slow_op_insn is
- when OP_MUL_H32 =>
- result := multiply_to_x.result(63 downto 32) &
- multiply_to_x.result(63 downto 32);
- when OP_MUL_H64 =>
- result := multiply_to_x.result(127 downto 64);
- when others =>
- -- i.e. OP_MUL_L64
- result := multiply_to_x.result(63 downto 0);
- end case;
else
- result := divider_to_x.write_reg_data;
overflow := divider_to_x.overflow;
end if;
if r.mul_in_progress = '1' and r.slow_op_oe = '1' then
v.div_in_progress := r.div_in_progress;
end if;
elsif r.mul_finish = '1' then
- result := r.e.write_data;
+ hold_wr_data := '1';
result_en := '1';
v.e.write_reg := gpr_to_gspr(r.slow_op_dest);
v.e.rc := r.slow_op_rc;
v.trace_next := '1';
end if;
- v.e.write_data := result;
+ if hold_wr_data = '0' then
+ v.e.write_data := alu_result;
+ else
+ v.e.write_data := r.e.write_data;
+ end if;
v.e.write_enable := result_en and not exception;
-- generate DSI or DSegI for load/store exceptions