core: Reorganize execute1

This breaks up the enormous if .. elsif .. case .. elsif statement in
execute1 in order to try to make it simpler and more understandable.
We now have decode2 deciding whether the instruction has a value to be
written back to a register (GPR, GSPR, FPR, etc.) rather than
individual cases in execute1 setting result_en.  The computation of
the data to be written back is now independent of detection of various
exception conditions.  We now have an if block determining if any
exception condition exists which prevents the next instruction from
being executed, then the case statement which performs actions such as
setting carry/overflow bits, determining if a trap exception exists,
doing branches, etc., then an if statement for all the r.busy = 1
cases (continuing execution of an instruction which was started in a
previous cycle, or writing SRR1 for an interrupt).

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
cache-tlb-parameters-2
Paul Mackerras 4 years ago
parent 658feabfd4
commit b0510fd1bb

@ -195,6 +195,7 @@ package common is
insn_type: insn_type_t; insn_type: insn_type_t;
nia: std_ulogic_vector(63 downto 0); nia: std_ulogic_vector(63 downto 0);
write_reg: gspr_index_t; write_reg: gspr_index_t;
write_reg_enable: std_ulogic;
read_reg1: gspr_index_t; read_reg1: gspr_index_t;
read_reg2: gspr_index_t; read_reg2: gspr_index_t;
read_data1: std_ulogic_vector(63 downto 0); read_data1: std_ulogic_vector(63 downto 0);
@ -232,7 +233,7 @@ package common is
end record; end record;
constant Decode2ToExecute1Init : Decode2ToExecute1Type := constant Decode2ToExecute1Init : Decode2ToExecute1Type :=
(valid => '0', unit => NONE, fac => NONE, insn_type => OP_ILLEGAL, (valid => '0', unit => NONE, fac => NONE, insn_type => OP_ILLEGAL,
bypass_data1 => '0', bypass_data2 => '0', bypass_data3 => '0', write_reg_enable => '0', bypass_data1 => '0', bypass_data2 => '0', bypass_data3 => '0',
bypass_cr => '0', lr => '0', rc => '0', oe => '0', invert_a => '0', addm1 => '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', 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', is_32bit => '0', is_signed => '0', xerc => xerc_init, reserve => '0', br_pred => '0',

@ -249,7 +249,8 @@ architecture behaviour of decode2 is
OP_MOD => "011", OP_MOD => "011",
OP_CNTZ => "100", -- countzero_result OP_CNTZ => "100", -- countzero_result
OP_MFSPR => "101", -- spr_result OP_MFSPR => "101", -- spr_result
OP_ISEL => "111", -- misc_result OP_ADDG6S => "111", -- misc_result
OP_ISEL => "111",
OP_DARN => "111", OP_DARN => "111",
OP_MFMSR => "111", OP_MFMSR => "111",
OP_MFCR => "111", OP_MFCR => "111",
@ -264,6 +265,12 @@ architecture behaviour of decode2 is
OP_DIV => "011", OP_DIV => "011",
OP_DIVE => "011", OP_DIVE => "011",
OP_MOD => "011", OP_MOD => "011",
OP_ADDG6S => "001", -- misc_result
OP_ISEL => "010",
OP_DARN => "011",
OP_MFMSR => "100",
OP_MFCR => "101",
OP_SETB => "110",
others => "000" others => "000"
); );


@ -438,6 +445,7 @@ begin
v.e.read_data3 := decoded_reg_c.data; v.e.read_data3 := decoded_reg_c.data;
v.e.bypass_data3 := gpr_c_bypass; v.e.bypass_data3 := gpr_c_bypass;
v.e.write_reg := decoded_reg_o.reg; v.e.write_reg := decoded_reg_o.reg;
v.e.write_reg_enable := decoded_reg_o.reg_valid;
v.e.rc := decode_rc(d_in.decode.rc, d_in.insn); v.e.rc := decode_rc(d_in.decode.rc, d_in.insn);
if not (d_in.decode.insn_type = OP_MUL_H32 or d_in.decode.insn_type = OP_MUL_H64) then if not (d_in.decode.insn_type = OP_MUL_H32 or d_in.decode.insn_type = OP_MUL_H64) then
v.e.oe := decode_oe(d_in.decode.rc, d_in.insn); v.e.oe := decode_oe(d_in.decode.rc, d_in.insn);
@ -448,7 +456,13 @@ begin
v.e.invert_a := d_in.decode.invert_a; v.e.invert_a := d_in.decode.invert_a;
v.e.addm1 := '0'; v.e.addm1 := '0';
if d_in.decode.insn_type = OP_BC or d_in.decode.insn_type = OP_BCREG then if d_in.decode.insn_type = OP_BC or d_in.decode.insn_type = OP_BCREG then
-- add -1 to CTR
v.e.addm1 := '1'; v.e.addm1 := '1';
if d_in.insn(23) = '1' or
(d_in.decode.insn_type = OP_BCREG and d_in.insn(10) = '0') then
-- don't write decremented CTR if BO(2) = 1 or bcctr
v.e.write_reg_enable := '0';
end if;
end if; end if;
v.e.invert_out := d_in.decode.invert_out; v.e.invert_out := d_in.decode.invert_out;
v.e.input_carry := d_in.decode.input_carry; v.e.input_carry := d_in.decode.input_carry;
@ -472,7 +486,7 @@ begin
control_valid_in <= d_in.valid; control_valid_in <= d_in.valid;
control_sgl_pipe <= d_in.decode.sgl_pipe; control_sgl_pipe <= d_in.decode.sgl_pipe;


gpr_write_valid <= decoded_reg_o.reg_valid; gpr_write_valid <= v.e.write_reg_enable;
gpr_write <= decoded_reg_o.reg; gpr_write <= decoded_reg_o.reg;
gpr_bypassable <= '0'; gpr_bypassable <= '0';
if EX1_BYPASS and d_in.decode.unit = ALU then if EX1_BYPASS and d_in.decode.unit = ALU then

@ -53,6 +53,7 @@ end entity execute1;
architecture behaviour of execute1 is architecture behaviour of execute1 is
type reg_type is record type reg_type is record
e : Execute1ToWritebackType; e : Execute1ToWritebackType;
cur_instr : Decode2ToExecute1Type;
busy: std_ulogic; busy: std_ulogic;
terminate: std_ulogic; terminate: std_ulogic;
fp_exception_next : std_ulogic; fp_exception_next : std_ulogic;
@ -60,17 +61,10 @@ architecture behaviour of execute1 is
prev_op : insn_type_t; prev_op : insn_type_t;
lr_update : std_ulogic; lr_update : std_ulogic;
next_lr : std_ulogic_vector(63 downto 0); 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_in_progress : std_ulogic;
mul_finish : std_ulogic; mul_finish : std_ulogic;
div_in_progress : std_ulogic; div_in_progress : std_ulogic;
cntz_in_progress : std_ulogic; cntz_in_progress : std_ulogic;
slow_op_insn : insn_type_t;
slow_op_dest : gpr_index_t;
slow_op_rc : std_ulogic;
slow_op_oe : std_ulogic;
slow_op_xerc : xer_common_t;
last_nia : std_ulogic_vector(63 downto 0); last_nia : std_ulogic_vector(63 downto 0);
redirect : std_ulogic; redirect : std_ulogic;
abs_br : std_ulogic; abs_br : std_ulogic;
@ -82,10 +76,10 @@ architecture behaviour of execute1 is
end record; end record;
constant reg_type_init : reg_type := constant reg_type_init : reg_type :=
(e => Execute1ToWritebackInit, (e => Execute1ToWritebackInit,
cur_instr => Decode2ToExecute1Init,
busy => '0', lr_update => '0', terminate => '0', busy => '0', lr_update => '0', terminate => '0',
fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL, fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL,
mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', cntz_in_progress => '0', mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', cntz_in_progress => '0',
slow_op_insn => OP_ILLEGAL, slow_op_rc => '0', slow_op_oe => '0', slow_op_xerc => xerc_init,
next_lr => (others => '0'), last_nia => (others => '0'), next_lr => (others => '0'), last_nia => (others => '0'),
redirect => '0', abs_br => '0', do_intr => '0', vector => 0, redirect => '0', abs_br => '0', do_intr => '0', vector => 0,
br_offset => (others => '0'), redir_mode => "0000", br_offset => (others => '0'), redir_mode => "0000",
@ -112,6 +106,7 @@ architecture behaviour of execute1 is
signal spr_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 result_mux_sel: std_ulogic_vector(2 downto 0);
signal sub_mux_sel: std_ulogic_vector(2 downto 0); signal sub_mux_sel: std_ulogic_vector(2 downto 0);
signal current: Decode2ToExecute1Type;


-- multiply signals -- multiply signals
signal x_to_multiply: MultiplyInputType; signal x_to_multiply: MultiplyInputType;
@ -294,10 +289,10 @@ begin


terminate_out <= r.terminate; terminate_out <= r.terminate;


current <= e_in when r.busy = '0' else r.cur_instr;

-- Result mux -- Result mux
result_mux_sel <= e_in.result_sel when r.busy = '0' else r.resmux; with current.result_sel select alu_result <=
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", adder_result when "000",
logical_result when "001", logical_result when "001",
rotator_result when "010", rotator_result when "010",
@ -333,9 +328,12 @@ begin
variable a_inv : std_ulogic_vector(63 downto 0); variable a_inv : std_ulogic_vector(63 downto 0);
variable b_or_m1 : 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 addg6s : std_ulogic_vector(63 downto 0);
variable isel_result : std_ulogic_vector(63 downto 0);
variable darn : std_ulogic_vector(63 downto 0);
variable mfcr_result : std_ulogic_vector(63 downto 0);
variable setb_result : std_ulogic_vector(63 downto 0);
variable newcrf : std_ulogic_vector(3 downto 0); variable newcrf : std_ulogic_vector(3 downto 0);
variable sum_with_carry : std_ulogic_vector(64 downto 0); variable sum_with_carry : std_ulogic_vector(64 downto 0);
variable result_en : std_ulogic;
variable crnum : crnum_t; variable crnum : crnum_t;
variable crbit : integer range 0 to 31; variable crbit : integer range 0 to 31;
variable scrnum : crnum_t; variable scrnum : crnum_t;
@ -375,7 +373,6 @@ begin
variable fv : Execute1ToFPUType; variable fv : Execute1ToFPUType;
begin begin
sum_with_carry := (others => '0'); sum_with_carry := (others => '0');
result_en := '0';
newcrf := (others => '0'); newcrf := (others => '0');
is_branch := '0'; is_branch := '0';
taken_branch := '0'; taken_branch := '0';
@ -400,7 +397,7 @@ begin
-- (SO, OV[32] and CA[32]) are only modified by instructions that are -- (SO, OV[32] and CA[32]) are only modified by instructions that are
-- handled here, we can just forward the result being sent to -- handled here, we can just forward the result being sent to
-- writeback. -- writeback.
if r.e.write_xerc_enable = '1' then if r.e.write_xerc_enable = '1' or r.busy = '1' then
v.e.xerc := r.e.xerc; v.e.xerc := r.e.xerc;
else else
v.e.xerc := e_in.xerc; v.e.xerc := e_in.xerc;
@ -422,7 +419,6 @@ begin
v.cntz_in_progress := '0'; v.cntz_in_progress := '0';
v.mul_finish := '0'; v.mul_finish := '0';


misc_result <= (others => '0');
spr_result <= (others => '0'); spr_result <= (others => '0');
spr_val := (others => '0'); spr_val := (others => '0');


@ -440,6 +436,8 @@ begin
sum_with_carry := ppc_adde(a_inv, b_or_m1, sum_with_carry := ppc_adde(a_inv, b_or_m1,
decode_input_carry(e_in.input_carry, v.e.xerc)); decode_input_carry(e_in.input_carry, v.e.xerc));
adder_result <= sum_with_carry(63 downto 0); adder_result <= sum_with_carry(63 downto 0);
carry_32 := sum_with_carry(32) xor a_inv(32) xor b_in(32);
carry_64 := sum_with_carry(64);


-- signals to multiply and divide units -- signals to multiply and divide units
sign1 := '0'; sign1 := '0';
@ -513,7 +511,7 @@ begin
x_to_divider.divisor <= x"00000000" & std_ulogic_vector(abs2(31 downto 0)); x_to_divider.divisor <= x"00000000" & std_ulogic_vector(abs2(31 downto 0));
end if; end if;


case sub_mux_sel(1 downto 0) is case current.sub_select(1 downto 0) is
when "00" => when "00" =>
muldiv_result <= multiply_to_x.result(63 downto 0); muldiv_result <= multiply_to_x.result(63 downto 0);
when "01" => when "01" =>
@ -525,6 +523,117 @@ begin
muldiv_result <= divider_to_x.write_reg_data; muldiv_result <= divider_to_x.write_reg_data;
end case; end case;


-- Compute misc_result
case current.sub_select is
when "000" =>
misc_result <= (others => '0');
when "001" =>
-- addg6s
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
addg6s(lo + 3 downto lo) := "0110";
end if;
end loop;
if sum_with_carry(64) = '0' then
addg6s(63 downto 60) := "0110";
end if;
misc_result <= addg6s;
when "010" =>
-- isel
crbit := to_integer(unsigned(insn_bc(e_in.insn)));
if cr_in(31-crbit) = '1' then
isel_result := a_in;
else
isel_result := b_in;
end if;
misc_result <= isel_result;
when "011" =>
-- darn
darn := (others => '1');
if random_err = '0' then
case e_in.insn(17 downto 16) is
when "00" =>
darn := x"00000000" & random_cond(31 downto 0);
when "10" =>
darn := random_raw;
when others =>
darn := random_cond;
end case;
end if;
misc_result <= darn;
when "100" =>
-- mfmsr
misc_result <= ctrl.msr;
when "101" =>
if e_in.insn(20) = '0' then
-- mfcr
mfcr_result := x"00000000" & cr_in;
else
-- mfocrf
crnum := fxm_to_num(insn_fxm(e_in.insn));
mfcr_result := (others => '0');
for i in 0 to 7 loop
lo := (7-i)*4;
hi := lo + 3;
if crnum = i then
mfcr_result(hi downto lo) := cr_in(hi downto lo);
end if;
end loop;
end if;
misc_result <= mfcr_result;
when "110" =>
-- setb
bfa := insn_bfa(e_in.insn);
crbit := to_integer(unsigned(bfa)) * 4;
setb_result := (others => '0');
if cr_in(31 - crbit) = '1' then
setb_result := (others => '1');
elsif cr_in(30 - crbit) = '1' then
setb_result(0) := '1';
end if;
misc_result <= setb_result;
when others =>
misc_result <= (others => '0');
end case;

-- compute comparison results
-- Note, we have done RB - RA, not RA - RB
if e_in.insn_type = OP_CMP then
l := insn_l(e_in.insn);
else
l := not e_in.is_32bit;
end if;
zerolo := not (or (a_in(31 downto 0) xor b_in(31 downto 0)));
zerohi := not (or (a_in(63 downto 32) xor b_in(63 downto 32)));
if zerolo = '1' and (l = '0' or zerohi = '1') then
-- values are equal
trapval := "00100";
else
if l = '1' then
-- 64-bit comparison
msb_a := a_in(63);
msb_b := b_in(63);
else
-- 32-bit comparison
msb_a := a_in(31);
msb_b := b_in(31);
end if;
if msb_a /= msb_b then
-- Subtraction might overflow, but
-- comparison is clear from MSB difference.
-- for signed, 0 is greater; for unsigned, 1 is greater
trapval := msb_a & msb_b & '0' & msb_b & msb_a;
else
-- Subtraction cannot overflow since MSBs are equal.
-- carry = 1 indicates RA is smaller (signed or unsigned)
a_lt := (not l and carry_32) or (l and carry_64);
trapval := a_lt & not a_lt & '0' & a_lt & not a_lt;
end if;
end if;

ctrl_tmp <= ctrl; ctrl_tmp <= ctrl;
-- FIXME: run at 512MHz not core freq -- FIXME: run at 512MHz not core freq
ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1); ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1);
@ -577,38 +686,20 @@ begin
v.prev_op := e_in.insn_type; v.prev_op := e_in.insn_type;
end if; end if;


if ctrl.irq_state = WRITE_SRR1 then -- Determine if there is any exception to be taken
v.e.exc_write_reg := fast_spr_num(SPR_SRR1); -- before/instead of executing this instruction
v.e.exc_write_data := ctrl.srr1; if valid_in = '1' and e_in.second = '0' then
v.e.exc_write_enable := '1';
ctrl_tmp.msr(MSR_SF) <= '1';
ctrl_tmp.msr(MSR_EE) <= '0';
ctrl_tmp.msr(MSR_PR) <= '0';
ctrl_tmp.msr(MSR_SE) <= '0';
ctrl_tmp.msr(MSR_BE) <= '0';
ctrl_tmp.msr(MSR_FP) <= '0';
ctrl_tmp.msr(MSR_FE0) <= '0';
ctrl_tmp.msr(MSR_FE1) <= '0';
ctrl_tmp.msr(MSR_IR) <= '0';
ctrl_tmp.msr(MSR_DR) <= '0';
ctrl_tmp.msr(MSR_RI) <= '0';
ctrl_tmp.msr(MSR_LE) <= '1';
v.e.valid := '1';
v.trace_next := '0';
v.fp_exception_next := '0';
report "Writing SRR1: " & to_hstring(ctrl.srr1);

elsif valid_in = '1' and e_in.second = '0' and
((HAS_FPU and r.fp_exception_next = '1') or r.trace_next = '1') then
if HAS_FPU and r.fp_exception_next = '1' then if HAS_FPU and r.fp_exception_next = '1' then
-- This is used for FP-type program interrupts that -- This is used for FP-type program interrupts that
-- become pending due to MSR[FE0,FE1] changing from 00 to non-zero. -- become pending due to MSR[FE0,FE1] changing from 00 to non-zero.
exception := '1';
v.vector := 16#700#; v.vector := 16#700#;
ctrl_tmp.srr1(63 - 43) <= '1'; ctrl_tmp.srr1(63 - 43) <= '1';
ctrl_tmp.srr1(63 - 47) <= '1'; ctrl_tmp.srr1(63 - 47) <= '1';
else elsif r.trace_next = '1' then
-- Generate a trace interrupt rather than executing the next instruction -- Generate a trace interrupt rather than executing the next instruction
-- or taking any asynchronous interrupt -- or taking any asynchronous interrupt
exception := '1';
v.vector := 16#d00#; v.vector := 16#d00#;
ctrl_tmp.srr1(63 - 33) <= '1'; ctrl_tmp.srr1(63 - 33) <= '1';
if r.prev_op = OP_LOAD or r.prev_op = OP_ICBI or r.prev_op = OP_ICBT or if r.prev_op = OP_LOAD or r.prev_op = OP_ICBI or r.prev_op = OP_ICBT or
@ -617,48 +708,38 @@ begin
elsif r.prev_op = OP_STORE or r.prev_op = OP_DCBZ or r.prev_op = OP_DCBTST then elsif r.prev_op = OP_STORE or r.prev_op = OP_DCBZ or r.prev_op = OP_DCBTST then
ctrl_tmp.srr1(63 - 36) <= '1'; ctrl_tmp.srr1(63 - 36) <= '1';
end if; end if;
end if;
exception := '1';

elsif irq_valid = '1' and valid_in = '1' and e_in.second = '0' then
-- we need two cycles to write srr0 and 1
-- will need more when we have to write HEIR
-- Don't deliver the interrupt until we have a valid instruction
-- coming in, so we have a valid NIA to put in SRR0.
exception := '1';


elsif valid_in = '1' and ctrl.msr(MSR_PR) = '1' and elsif irq_valid = '1' then
instr_is_privileged(e_in.insn_type, e_in.insn) then -- Don't deliver the interrupt until we have a valid instruction
-- generate a program interrupt -- coming in, so we have a valid NIA to put in SRR0.
exception := '1'; exception := '1';
v.vector := 16#700#;
-- set bit 45 to indicate privileged instruction type interrupt
ctrl_tmp.srr1(63 - 45) <= '1';
report "privileged instruction";


elsif not HAS_FPU and valid_in = '1' and e_in.fac = FPU then elsif ctrl.msr(MSR_PR) = '1' and instr_is_privileged(e_in.insn_type, e_in.insn) then
-- make lfd/stfd/lfs/stfs etc. illegal in no-FPU implementations -- generate a program interrupt
illegal := '1'; exception := '1';
v.vector := 16#700#;
-- set bit 45 to indicate privileged instruction type interrupt
ctrl_tmp.srr1(63 - 45) <= '1';
report "privileged instruction";


elsif HAS_FPU and valid_in = '1' and ctrl.msr(MSR_FP) = '0' and e_in.fac = FPU then elsif not HAS_FPU and e_in.fac = FPU then
-- generate a floating-point unavailable interrupt -- make lfd/stfd/lfs/stfs etc. illegal in no-FPU implementations
exception := '1'; illegal := '1';
v.vector := 16#800#;
report "FP unavailable interrupt";


elsif valid_in = '1' and e_in.unit = ALU then elsif HAS_FPU and ctrl.msr(MSR_FP) = '0' and e_in.fac = FPU then
-- generate a floating-point unavailable interrupt
exception := '1';
v.vector := 16#800#;
report "FP unavailable interrupt";
end if;
end if;


if valid_in = '1' and exception = '0' and illegal = '0' and e_in.unit = ALU then
report "execute nia " & to_hstring(e_in.nia); report "execute nia " & to_hstring(e_in.nia);


v.cur_instr := e_in;
v.next_lr := next_nia;
v.e.valid := '1'; v.e.valid := '1';
v.e.write_reg := e_in.write_reg;
v.slow_op_insn := e_in.insn_type;
v.slow_op_dest := gspr_to_gpr(e_in.write_reg);
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 case_0: case e_in.insn_type is


@ -689,101 +770,48 @@ begin
end if; end if;
when OP_NOP | OP_DCBF | OP_DCBST | OP_DCBT | OP_DCBTST | OP_ICBT => when OP_NOP | OP_DCBF | OP_DCBST | OP_DCBT | OP_DCBTST | OP_ICBT =>
-- Do nothing -- Do nothing
when OP_ADD | OP_CMP | OP_TRAP => when OP_ADD =>
carry_32 := sum_with_carry(32) xor a_inv(32) xor b_in(32); if e_in.output_carry = '1' then
carry_64 := sum_with_carry(64); if e_in.input_carry /= OV then
if e_in.insn_type = OP_ADD then set_carry(v.e, carry_32, carry_64);
if e_in.output_carry = '1' then
if e_in.input_carry /= OV then
set_carry(v.e, carry_32, carry_64);
else
v.e.xerc.ov := carry_64;
v.e.xerc.ov32 := carry_32;
v.e.write_xerc_enable := '1';
end if;
end if;
if e_in.oe = '1' then
set_ov(v.e,
calc_ov(a_inv(63), b_in(63), carry_64, sum_with_carry(63)),
calc_ov(a_inv(31), b_in(31), carry_32, sum_with_carry(31)));
end if;
result_en := '1';
else
-- trap, CMP and CMPL instructions
-- Note, we have done RB - RA, not RA - RB
if e_in.insn_type = OP_CMP then
l := insn_l(e_in.insn);
else
l := not e_in.is_32bit;
end if;
zerolo := not (or (a_in(31 downto 0) xor b_in(31 downto 0)));
zerohi := not (or (a_in(63 downto 32) xor b_in(63 downto 32)));
if zerolo = '1' and (l = '0' or zerohi = '1') then
-- values are equal
trapval := "00100";
else else
if l = '1' then v.e.xerc.ov := carry_64;
-- 64-bit comparison v.e.xerc.ov32 := carry_32;
msb_a := a_in(63); v.e.write_xerc_enable := '1';
msb_b := b_in(63);
else
-- 32-bit comparison
msb_a := a_in(31);
msb_b := b_in(31);
end if;
if msb_a /= msb_b then
-- Subtraction might overflow, but
-- comparison is clear from MSB difference.
-- for signed, 0 is greater; for unsigned, 1 is greater
trapval := msb_a & msb_b & '0' & msb_b & msb_a;
else
-- Subtraction cannot overflow since MSBs are equal.
-- carry = 1 indicates RA is smaller (signed or unsigned)
a_lt := (not l and carry_32) or (l and carry_64);
trapval := a_lt & not a_lt & '0' & a_lt & not a_lt;
end if;
end if;
if e_in.insn_type = OP_CMP then
if e_in.is_signed = '1' then
newcrf := trapval(4 downto 2) & v.e.xerc.so;
else
newcrf := trapval(1 downto 0) & trapval(2) & v.e.xerc.so;
end if;
bf := insn_bf(e_in.insn);
crnum := to_integer(unsigned(bf));
v.e.write_cr_enable := '1';
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) := newcrf;
end loop;
else
-- trap instructions (tw, twi, td, tdi)
v.vector := 16#700#;
-- set bit 46 to say trap occurred
ctrl_tmp.srr1(63 - 46) <= '1';
if or (trapval and insn_to(e_in.insn)) = '1' then
-- generate trap-type program interrupt
exception := '1';
report "trap";
end if;
end if; end if;
end if; end if;
when OP_ADDG6S => if e_in.oe = '1' then
addg6s := (others => '0'); set_ov(v.e,
for i in 0 to 14 loop calc_ov(a_inv(63), b_in(63), carry_64, sum_with_carry(63)),
lo := i * 4; calc_ov(a_inv(31), b_in(31), carry_32, sum_with_carry(31)));
hi := (i + 1) * 4; end if;
if (a_in(hi) xor b_in(hi) xor sum_with_carry(hi)) = '0' then when OP_CMP =>
addg6s(lo + 3 downto lo) := "0110"; -- CMP and CMPL instructions
end if; if e_in.is_signed = '1' then
newcrf := trapval(4 downto 2) & v.e.xerc.so;
else
newcrf := trapval(1 downto 0) & trapval(2) & v.e.xerc.so;
end if;
bf := insn_bf(e_in.insn);
crnum := to_integer(unsigned(bf));
v.e.write_cr_enable := '1';
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) := newcrf;
end loop; end loop;
if sum_with_carry(64) = '0' then when OP_TRAP =>
addg6s(63 downto 60) := "0110"; -- trap instructions (tw, twi, td, tdi)
v.vector := 16#700#;
-- set bit 46 to say trap occurred
ctrl_tmp.srr1(63 - 46) <= '1';
if or (trapval and insn_to(e_in.insn)) = '1' then
-- generate trap-type program interrupt
exception := '1';
report "trap";
end if; end if;
misc_result <= addg6s; when OP_ADDG6S =>
result_en := '1';
when OP_CMPRB => when OP_CMPRB =>
newcrf := ppc_cmprb(a_in, b_in, insn_l(e_in.insn)); newcrf := ppc_cmprb(a_in, b_in, insn_l(e_in.insn));
bf := insn_bf(e_in.insn); bf := insn_bf(e_in.insn);
@ -802,7 +830,6 @@ begin
newcrf & newcrf & newcrf & newcrf; newcrf & newcrf & newcrf & newcrf;
when OP_AND | OP_OR | OP_XOR | OP_POPCNT | OP_PRTY | OP_CMPB | OP_EXTS | when OP_AND | OP_OR | OP_XOR | OP_POPCNT | OP_PRTY | OP_CMPB | OP_EXTS |
OP_BPERM | OP_BCD => OP_BPERM | OP_BCD =>
result_en := '1';
when OP_B => when OP_B =>
is_branch := '1'; is_branch := '1';
taken_branch := '1'; taken_branch := '1';
@ -812,12 +839,8 @@ begin
end if; end if;
when OP_BC => when OP_BC =>
-- read_data1 is CTR -- read_data1 is CTR
v.e.write_reg := fast_spr_num(SPR_CTR);
bo := insn_bo(e_in.insn); bo := insn_bo(e_in.insn);
bi := insn_bi(e_in.insn); bi := insn_bi(e_in.insn);
if bo(4-2) = '0' then
result_en := '1';
end if;
is_branch := '1'; is_branch := '1';
taken_branch := ppc_bc_taken(bo, bi, cr_in, a_in); taken_branch := ppc_bc_taken(bo, bi, cr_in, a_in);
abs_branch := insn_aa(e_in.insn); abs_branch := insn_aa(e_in.insn);
@ -827,12 +850,8 @@ begin
when OP_BCREG => when OP_BCREG =>
-- read_data1 is CTR -- read_data1 is CTR
-- read_data2 is target register (CTR, LR or TAR) -- read_data2 is target register (CTR, LR or TAR)
v.e.write_reg := fast_spr_num(SPR_CTR);
bo := insn_bo(e_in.insn); bo := insn_bo(e_in.insn);
bi := insn_bi(e_in.insn); bi := insn_bi(e_in.insn);
if bo(4-2) = '0' and e_in.insn(10) = '0' then
result_en := '1';
end if;
is_branch := '1'; is_branch := '1';
taken_branch := ppc_bc_taken(bo, bi, cr_in, a_in); taken_branch := ppc_bc_taken(bo, bi, cr_in, a_in);
abs_branch := '1'; abs_branch := '1';
@ -868,13 +887,6 @@ begin
v.cntz_in_progress := '1'; v.cntz_in_progress := '1';
v.busy := '1'; v.busy := '1';
when OP_ISEL => when OP_ISEL =>
crbit := to_integer(unsigned(insn_bc(e_in.insn)));
if cr_in(31-crbit) = '1' then
misc_result <= a_in;
else
misc_result <= b_in;
end if;
result_en := '1';
when OP_CROP => when OP_CROP =>
cr_op := insn_cr(e_in.insn); cr_op := insn_cr(e_in.insn);
report "CR OP " & to_hstring(cr_op); report "CR OP " & to_hstring(cr_op);
@ -927,27 +939,11 @@ begin
v.e.write_cr_data := newcrf & newcrf & newcrf & newcrf & v.e.write_cr_data := newcrf & newcrf & newcrf & newcrf &
newcrf & newcrf & newcrf & newcrf; newcrf & newcrf & newcrf & newcrf;
when OP_DARN => when OP_DARN =>
if random_err = '0' then
case e_in.insn(17 downto 16) is
when "00" =>
misc_result <= x"00000000" & random_cond(31 downto 0);
when "10" =>
misc_result <= random_raw;
when others =>
misc_result <= random_cond;
end case;
else
misc_result <= (others => '1');
end if;
result_en := '1';
when OP_MFMSR => when OP_MFMSR =>
misc_result <= ctrl.msr;
result_en := '1';
when OP_MFSPR => when OP_MFSPR =>
report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) & report "MFSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
"=" & to_hstring(a_in); "=" & to_hstring(a_in);
result_en := '1'; if is_fast_spr(e_in.read_reg1) = '1' then
if is_fast_spr(e_in.read_reg1) then
spr_val := a_in; spr_val := a_in;
if decode_spr_num(e_in.insn) = SPR_XER then 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 -- bits 0:31 and 35:43 are treated as reserved and return 0s when read using mfxer
@ -982,7 +978,7 @@ begin
when others => when others =>
-- mfspr from unimplemented SPRs should be a nop in -- mfspr from unimplemented SPRs should be a nop in
-- supervisor mode and a program interrupt for user mode -- supervisor mode and a program interrupt for user mode
if ctrl.msr(MSR_PR) = '1' then if is_fast_spr(e_in.read_reg1) = '0' and ctrl.msr(MSR_PR) = '1' then
illegal := '1'; illegal := '1';
end if; end if;
end case; end case;
@ -990,22 +986,6 @@ begin
spr_result <= spr_val; spr_result <= spr_val;


when OP_MFCR => when OP_MFCR =>
if e_in.insn(20) = '0' then
-- mfcr
misc_result <= x"00000000" & cr_in;
else
-- mfocrf
crnum := fxm_to_num(insn_fxm(e_in.insn));
misc_result <= (others => '0');
for i in 0 to 7 loop
lo := (7-i)*4;
hi := lo + 3;
if crnum = i then
misc_result(hi downto lo) <= cr_in(hi downto lo);
end if;
end loop;
end if;
result_en := '1';
when OP_MTCRF => when OP_MTCRF =>
v.e.write_cr_enable := '1'; v.e.write_cr_enable := '1';
if e_in.insn(20) = '0' then if e_in.insn(20) = '0' then
@ -1045,7 +1025,6 @@ begin
report "MTSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) & report "MTSPR to SPR " & integer'image(decode_spr_num(e_in.insn)) &
"=" & to_hstring(c_in); "=" & to_hstring(c_in);
if is_fast_spr(e_in.write_reg) then if is_fast_spr(e_in.write_reg) then
result_en := '1';
if decode_spr_num(e_in.insn) = SPR_XER then if decode_spr_num(e_in.insn) = SPR_XER then
v.e.xerc.so := c_in(63-32); v.e.xerc.so := c_in(63-32);
v.e.xerc.ov := c_in(63-33); v.e.xerc.ov := c_in(63-33);
@ -1073,16 +1052,7 @@ begin
if e_in.output_carry = '1' then if e_in.output_carry = '1' then
set_carry(v.e, rotator_carry, rotator_carry); set_carry(v.e, rotator_carry, rotator_carry);
end if; end if;
result_en := '1';
when OP_SETB => when OP_SETB =>
bfa := insn_bfa(e_in.insn);
crbit := to_integer(unsigned(bfa)) * 4;
misc_result <= (others => '0');
if cr_in(31 - crbit) = '1' then
misc_result <= (others => '1');
elsif cr_in(30 - crbit) = '1' then
misc_result(0) <= '1';
end if;


when OP_ISYNC => when OP_ISYNC =>
v.redirect := '1'; v.redirect := '1';
@ -1108,8 +1078,6 @@ begin
report "illegal"; report "illegal";
end case; end case;


v.e.rc := e_in.rc and valid_in;

-- Mispredicted branches cause a redirect -- Mispredicted branches cause a redirect
if is_branch = '1' then if is_branch = '1' then
if taken_branch = '1' then if taken_branch = '1' then
@ -1126,26 +1094,7 @@ begin
end if; end if;
end if; end if;


-- Update LR on the next cycle after a branch link elsif valid_in = '1' and exception = '0' and illegal = '0' then
-- If we're not writing back anything else, we can write back LR
-- this cycle, otherwise we take an extra cycle. We use the
-- exc_write path since next_nia is written through that path
-- in other places.
if e_in.lr = '1' then
if result_en = '0' then
v.e.exc_write_enable := '1';
v.e.exc_write_data := next_nia;
v.e.exc_write_reg := fast_spr_num(SPR_LR);
else
v.lr_update := '1';
v.next_lr := next_nia;
v.e.valid := '0';
report "Delayed LR update to " & to_hstring(next_nia);
v.busy := '1';
end if;
end if;

elsif valid_in = '1' then
-- instruction for other units, i.e. LDST -- instruction for other units, i.e. LDST
if e_in.unit = LDST then if e_in.unit = LDST then
lv.valid := '1'; lv.valid := '1';
@ -1164,23 +1113,28 @@ begin
-- valid_in = 0. Hence they don't happen in the same cycle as any of -- valid_in = 0. Hence they don't happen in the same cycle as any of
-- the cases above which depend on valid_in = 1. -- the cases above which depend on valid_in = 1.


if r.redirect = '1' then if ctrl.irq_state = WRITE_SRR1 then
v.e.valid := '1'; v.e.exc_write_reg := fast_spr_num(SPR_SRR1);
end if; v.e.exc_write_data := ctrl.srr1;
if r.lr_update = '1' then
v.e.exc_write_enable := '1'; v.e.exc_write_enable := '1';
v.e.exc_write_data := r.next_lr; ctrl_tmp.msr(MSR_SF) <= '1';
v.e.exc_write_reg := fast_spr_num(SPR_LR); ctrl_tmp.msr(MSR_EE) <= '0';
v.e.valid := '1'; ctrl_tmp.msr(MSR_PR) <= '0';
-- Keep r.e.write_data unchanged next cycle in case it is needed ctrl_tmp.msr(MSR_SE) <= '0';
-- for a forwarded result (e.g. for CTR). ctrl_tmp.msr(MSR_BE) <= '0';
hold_wr_data := '1'; ctrl_tmp.msr(MSR_FP) <= '0';
ctrl_tmp.msr(MSR_FE0) <= '0';
ctrl_tmp.msr(MSR_FE1) <= '0';
ctrl_tmp.msr(MSR_IR) <= '0';
ctrl_tmp.msr(MSR_DR) <= '0';
ctrl_tmp.msr(MSR_RI) <= '0';
ctrl_tmp.msr(MSR_LE) <= '1';
v.trace_next := '0';
v.fp_exception_next := '0';
report "Writing SRR1: " & to_hstring(ctrl.srr1);

elsif r.cntz_in_progress = '1' then elsif r.cntz_in_progress = '1' then
-- cnt[lt]z always takes two cycles -- cnt[lt]z always takes two cycles
result_en := '1';
v.e.write_reg := gpr_to_gspr(r.slow_op_dest);
v.e.rc := r.slow_op_rc;
v.e.xerc := r.slow_op_xerc;
v.e.valid := '1'; v.e.valid := '1';
elsif r.mul_in_progress = '1' or r.div_in_progress = '1' then elsif r.mul_in_progress = '1' or r.div_in_progress = '1' then
if (r.mul_in_progress = '1' and multiply_to_x.valid = '1') or if (r.mul_in_progress = '1' and multiply_to_x.valid = '1') or
@ -1190,23 +1144,21 @@ begin
else else
overflow := divider_to_x.overflow; overflow := divider_to_x.overflow;
end if; end if;
if r.mul_in_progress = '1' and r.slow_op_oe = '1' then if r.mul_in_progress = '1' and current.oe = '1' then
-- have to wait until next cycle for overflow indication -- have to wait until next cycle for overflow indication
v.mul_finish := '1'; v.mul_finish := '1';
v.busy := '1'; v.busy := '1';
else else
result_en := '1'; v.e.write_xerc_enable := current.oe;
v.e.write_reg := gpr_to_gspr(r.slow_op_dest);
v.e.rc := r.slow_op_rc;
v.e.xerc := r.slow_op_xerc;
v.e.write_xerc_enable := r.slow_op_oe;
-- We must test oe because the RC update code in writeback -- We must test oe because the RC update code in writeback
-- will use the xerc value to set CR0:SO so we must not clobber -- will use the xerc value to set CR0:SO so we must not clobber
-- xerc if OE wasn't set. -- xerc if OE wasn't set.
if r.slow_op_oe = '1' then if current.oe = '1' then
v.e.xerc.ov := overflow; v.e.xerc.ov := overflow;
v.e.xerc.ov32 := overflow; v.e.xerc.ov32 := overflow;
v.e.xerc.so := r.slow_op_xerc.so or overflow; if overflow = '1' then
v.e.xerc.so := '1';
end if;
end if; end if;
v.e.valid := '1'; v.e.valid := '1';
end if; end if;
@ -1217,16 +1169,19 @@ begin
end if; end if;
elsif r.mul_finish = '1' then elsif r.mul_finish = '1' then
hold_wr_data := '1'; hold_wr_data := '1';
result_en := '1'; v.e.write_xerc_enable := current.oe;
v.e.write_reg := gpr_to_gspr(r.slow_op_dest);
v.e.rc := r.slow_op_rc;
v.e.xerc := r.slow_op_xerc;
v.e.write_xerc_enable := r.slow_op_oe;
v.e.xerc.ov := multiply_to_x.overflow; v.e.xerc.ov := multiply_to_x.overflow;
v.e.xerc.ov32 := multiply_to_x.overflow; v.e.xerc.ov32 := multiply_to_x.overflow;
v.e.xerc.so := r.slow_op_xerc.so or multiply_to_x.overflow; if multiply_to_x.overflow = '1' then
v.e.xerc.so := '1';
end if;
v.e.valid := '1'; v.e.valid := '1';
end if; end if;
-- When doing delayed LR update, keep r.e.write_data unchanged
-- next cycle in case it is needed for a forwarded result (e.g. CTR).
if r.lr_update = '1' then
hold_wr_data := '1';
end if;


-- Generate FP-type program interrupt. fp_in.interrupt will only -- Generate FP-type program interrupt. fp_in.interrupt will only
-- be set during the execution of a FP instruction. -- be set during the execution of a FP instruction.
@ -1253,17 +1208,6 @@ begin
end if; end if;
end if; end if;


if do_trace = '1' then
v.trace_next := '1';
end if;

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 -- generate DSI or DSegI for load/store exceptions
-- or ISI or ISegI for instruction fetch exceptions -- or ISI or ISegI for instruction fetch exceptions
if l_in.exception = '1' then if l_in.exception = '1' then
@ -1297,10 +1241,52 @@ begin
v.do_intr := '1'; v.do_intr := '1';
end if; end if;


if do_trace = '1' then
v.trace_next := '1';
end if;

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_reg := current.write_reg;
v.e.write_enable := current.write_reg_enable and v.e.valid and not exception;
v.e.rc := current.rc and v.e.valid and not exception;

-- Update LR on the next cycle after a branch link
-- If we're not writing back anything else, we can write back LR
-- this cycle, otherwise we take an extra cycle. We use the
-- exc_write path since next_nia is written through that path
-- in other places.
if v.e.valid = '1' and exception = '0' and current.lr = '1' then
if current.write_reg_enable = '0' then
v.e.exc_write_enable := '1';
v.e.exc_write_data := next_nia;
v.e.exc_write_reg := fast_spr_num(SPR_LR);
else
v.lr_update := '1';
v.e.valid := '0';
report "Delayed LR update to " & to_hstring(next_nia);
v.busy := '1';
end if;
end if;
if r.lr_update = '1' then
v.e.exc_write_enable := '1';
v.e.exc_write_data := r.next_lr;
v.e.exc_write_reg := fast_spr_num(SPR_LR);
v.e.valid := '1';
end if;

-- Defer completion for one cycle when redirecting.
-- This also ensures r.busy = 1 when ctrl.irq_state = WRITE_SRR1
if v.redirect = '1' then if v.redirect = '1' then
v.busy := '1'; v.busy := '1';
v.e.valid := '0'; v.e.valid := '0';
end if; end if;
if r.redirect = '1' then
v.e.valid := '1';
end if;


-- Outputs to fetch1 -- Outputs to fetch1
f.redirect := r.redirect; f.redirect := r.redirect;

Loading…
Cancel
Save