constant RAMSPR_SPRG0 : ramspr_index := 2;
constant RAMSPR_SPRG2 : ramspr_index := 3;
constant RAMSPR_HSPRG0 : ramspr_index := 4;
+ constant RAMSPR_LR : ramspr_index := 5; -- must equal RAMSPR_CTR
+ constant RAMSPR_TAR : ramspr_index := 6;
-- Odd half:
constant RAMSPR_SRR1 : ramspr_index := 0;
constant RAMSPR_HSRR1 : ramspr_index := 1;
constant RAMSPR_SPRG1 : ramspr_index := 2;
constant RAMSPR_SPRG3 : ramspr_index := 3;
constant RAMSPR_HSPRG1 : ramspr_index := 4;
+ constant RAMSPR_CTR : ramspr_index := 5; -- must equal RAMSPR_LR
type ram_spr_info is record
index : ramspr_index;
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;
ramspr_wraddr : ramspr_index;
ramspr_write_even : std_ulogic;
ramspr_write_odd : std_ulogic;
+ dec_ctr : std_ulogic;
end record;
constant Decode2ToExecute1Init : Decode2ToExecute1Type :=
(valid => '0', unit => NONE, fac => NONE, insn_type => OP_ILLEGAL, instr_tag => instr_tag_init,
write_reg_enable => '0',
- lr => '0', br_abs => '0', rc => '0', oe => '0', invert_a => '0', addm1 => '0',
+ lr => '0', br_abs => '0', rc => '0', oe => '0', invert_a => '0',
invert_out => '0', input_carry => ZERO, output_carry => '0', input_cr => '0',
output_cr => '0', output_xer => '0',
is_32bit => '0', is_signed => '0', xerc => xerc_init, reserve => '0', br_pred => '0',
spr_is_ram => '0',
ramspr_even_rdaddr => 0, ramspr_odd_rdaddr => 0, ramspr_rd_odd => '0',
ramspr_wraddr => 0, ramspr_write_even => '0', ramspr_write_odd => '0',
+ dec_ctr => '0',
others => (others => '0'));
type MultiplyInputType is record
return to_integer(unsigned(insn(15 downto 11) & insn(20 downto 16)));
end;
function fast_spr_num(spr: spr_num_t) return gspr_index_t is
- variable n : integer range 0 to 31;
- -- tmp variable introduced as workaround for VCS compilation
- -- simulation was failing with subtype constraint mismatch error
- -- see GitHub PR #173
- variable tmp : std_ulogic_vector(4 downto 0);
begin
- case spr is
- when SPR_LR =>
- n := 0; -- N.B. decode2 relies on this specific value
- when SPR_CTR =>
- n := 1; -- N.B. decode2 relies on this specific value
- when SPR_TAR =>
- n := 13;
- when others =>
- n := 0;
- return "0000000";
- end case;
- tmp := std_ulogic_vector(to_unsigned(n, 5));
- return "01" & tmp;
+ return "0000000";
end;
function gspr_to_gpr(i: gspr_index_t) return gpr_index_t is
signal rst_dbg : std_ulogic;
signal alt_reset_d : std_ulogic;
+ signal sim_ex_dump: std_ulogic;
signal sim_cr_dump: std_ulogic;
-- Debug actions
dbg_gpr_addr => dbg_gpr_addr,
dbg_gpr_data => dbg_gpr_data,
sim_dump => terminate,
- sim_dump_done => sim_cr_dump,
+ sim_dump_done => sim_ex_dump,
log_out => log_data(255 downto 184)
);
execute1_0: entity work.execute1
generic map (
+ SIM => SIM,
EX1_BYPASS => EX1_BYPASS,
HAS_FPU => HAS_FPU,
HAS_SHORT_MULT => HAS_SHORT_MULT,
dc_events => dcache_events,
ic_events => icache_events,
terminate_out => terminate,
+ sim_dump => sim_ex_dump,
+ sim_dump_done => sim_cr_dump,
log_out => log_data(134 downto 120),
log_rd_addr => log_rd_addr,
log_rd_data => log_rd_data,
28 => (ALU, NONE, OP_AND, NONE, CONST_UI, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', ONE, '0', '0', NONE), -- andi.
29 => (ALU, NONE, OP_AND, NONE, CONST_UI_HI, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', ONE, '0', '0', NONE), -- andis.
0 => (ALU, NONE, OP_ATTN, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1', NONE), -- attn
- 18 => (ALU, NONE, OP_B, NONE, CONST_LI, NONE, SPR, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0', NONE), -- b
- 16 => (ALU, NONE, OP_BC, SPR, CONST_BD, NONE, SPR , '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0', NONE), -- bc
+ 18 => (ALU, NONE, OP_B, NONE, CONST_LI, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0', NONE), -- b
+ 16 => (ALU, NONE, OP_BC, NONE, CONST_BD, NONE, NONE, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0', NONE), -- bc
11 => (ALU, NONE, OP_CMP, RA, CONST_SI, NONE, NONE, '0', '1', '1', '0', ONE, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0', NONE), -- cmpi
10 => (ALU, NONE, OP_CMP, RA, CONST_UI, NONE, NONE, '0', '1', '1', '0', ONE, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- cmpli
34 => (LDST, NONE, OP_LOAD, RA_OR_ZERO, CONST_SI, NONE, RT, '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- lbz
-- addpcis
2#001# => (ALU, NONE, OP_ADD, CIA, CONST_DXHI4, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
-- bclr, bcctr, bctar
- 2#100# => (ALU, NONE, OP_BCREG, SPR, SPR, NONE, SPR, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0', NONE),
+ 2#100# => (ALU, NONE, OP_BCREG, NONE, NONE, NONE, SPR, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0', NONE),
-- isync
2#111# => (ALU, NONE, OP_ISYNC, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE),
-- rfid
begin
ret := (index => 0, isodd => '0', valid => '1');
case sprn is
+ when SPR_LR =>
+ ret.index := RAMSPR_LR;
+ when SPR_CTR =>
+ ret.index := RAMSPR_CTR;
+ ret.isodd := '1';
+ when SPR_TAR =>
+ ret.index := RAMSPR_TAR;
when SPR_SRR0 =>
ret.index := RAMSPR_SRR0;
when SPR_SRR1 =>
end if;
when 16 =>
- -- CTR may be needed as input to bc
- if f_in.insn(23) = '0' then
- v.ispr1 := fast_spr_num(SPR_CTR);
- v.ispro := fast_spr_num(SPR_CTR);
- elsif f_in.insn(0) = '1' then
- v.ispro := fast_spr_num(SPR_LR);
- end if;
-- Predict backward branches as taken, forward as untaken
v.br_pred := f_in.insn(15);
br_offset := resize(signed(f_in.insn(15 downto 2)), 24);
-- Unconditional branches are always taken
v.br_pred := '1';
br_offset := signed(f_in.insn(25 downto 2));
- if f_in.insn(0) = '1' then
- v.ispro := fast_spr_num(SPR_LR);
- end if;
when 19 =>
vi.override := not decode_op_19_valid(to_integer(unsigned(f_in.insn(5 downto 1) & f_in.insn(10 downto 6))));
op_19_bits := f_in.insn(5) & f_in.insn(3) & f_in.insn(2);
v.decode := decode_op_19_array(to_integer(unsigned(op_19_bits)));
- -- Work out ispr1/ispr2 independent of v.decode since they seem to be critical path
- if f_in.insn(2) = '0' then
- -- Could be OP_BCREG: bclr, bcctr, bctar
- -- Branch uses CTR as condition when BO(2) is 0. This is
- -- also used to indicate that CTR is modified (they go
- -- together).
- -- bcctr doesn't update CTR or use it in the branch condition
- if f_in.insn(23) = '0' and (f_in.insn(10) = '0' or f_in.insn(6) = '1') then
- v.ispr1 := fast_spr_num(SPR_CTR);
- v.ispro := fast_spr_num(SPR_CTR);
- elsif f_in.insn(0) = '1' then
- v.ispro := fast_spr_num(SPR_LR);
- end if;
- if f_in.insn(10) = '0' then
- v.ispr2 := fast_spr_num(SPR_LR);
- elsif f_in.insn(6) = '0' then
- v.ispr2 := fast_spr_num(SPR_CTR);
- else
- v.ispr2 := fast_spr_num(SPR_TAR);
- end if;
- end if;
-
when 24 =>
-- ori, special-case the standard NOP
if std_match(f_in.insn, "01100000000000000000000000000000") then
variable length : std_ulogic_vector(3 downto 0);
variable op : insn_type_t;
variable valid_in : std_ulogic;
+ variable decctr : std_ulogic;
begin
v := dc2;
end if;
op := d_in.decode.insn_type;
+ -- Does this instruction decrement CTR?
+ -- bc, bclr, bctar with BO(2) = 0 do, but not bcctr.
+ decctr := '0';
+ if d_in.insn(23) = '0' and
+ (op = OP_BC or
+ (op = OP_BCREG and not (d_in.insn(10) = '1' and d_in.insn(6) = '0'))) then
+ decctr := '1';
+ end if;
+ v.e.dec_ctr := decctr;
+
v.repeat := d_in.decode.repeat;
if d_in.decode.repeat /= NONE then
v.e.repeat := '1';
- elsif v.e.lr = '1' and decoded_reg_a.reg_valid = '1' then
- -- bcl/bclrl/bctarl that needs to write both CTR and LR has to be doubled
- v.e.repeat := '1';
end if;
v.e.spr_select := d_in.spr_info;
+ if decctr = '1' then
+ -- read and write CTR
+ v.e.ramspr_odd_rdaddr := RAMSPR_CTR;
+ v.e.ramspr_wraddr := RAMSPR_CTR;
+ v.e.ramspr_write_odd := '1';
+ end if;
+ if v.e.lr = '1' then
+ -- write LR
+ v.e.ramspr_wraddr := RAMSPR_LR;
+ v.e.ramspr_write_even := '1';
+ end if;
+
case op is
+ when OP_BCREG =>
+ if d_in.insn(10) = '0' then
+ v.e.ramspr_even_rdaddr := RAMSPR_LR;
+ elsif d_in.insn(6) = '0' then
+ v.e.ramspr_odd_rdaddr := RAMSPR_CTR;
+ v.e.ramspr_rd_odd := '1';
+ else
+ v.e.ramspr_even_rdaddr := RAMSPR_TAR;
+ end if;
when OP_MFSPR =>
v.e.ramspr_even_rdaddr := d_in.ram_spr.index;
v.e.ramspr_odd_rdaddr := d_in.ram_spr.index;
v.e.write_reg := decoded_reg_o.reg;
v.e.write_reg_enable := decoded_reg_o.reg_valid;
v.e.invert_a := d_in.decode.invert_a;
- v.e.addm1 := '0';
v.e.insn_type := op;
v.e.invert_out := d_in.decode.invert_out;
v.e.input_carry := d_in.decode.input_carry;
v.e.br_pred := d_in.br_pred;
v.e.result_sel := result_select(op);
v.e.sub_select := subresult_select(op);
- if op = OP_BC or op = OP_BCREG then
- if d_in.insn(23) = '0' and
- not (d_in.decode.insn_type = OP_BCREG and d_in.insn(10) = '0') then
- -- decrement CTR if BO(2) = 0 and not bcctr
- v.e.addm1 := '1';
- v.e.result_sel := "000"; -- select adder output
- end if;
- end if;
if op = OP_MFSPR then
if is_fast_spr(d_in.ispr1) = '1' then
v.e.result_sel := "000"; -- adder_result, effectively a_in
-- dc2.busy = 1 and dc2.e.valid = 1, thus this must be a repeated instruction.
-- Set up for the second iteration (if deferred = 1 this will all be ignored)
v.e.second := '1';
- case dc2.repeat is
- when DUPD =>
- -- update-form loads, 2nd instruction writes RA
- v.e.write_reg := dc2.e.read_reg1;
- when NONE =>
- -- bcl/bclrl/bctarl that needs to write both CTR and LR
- v.e.write_reg(0) := '0'; -- point to LR
- v.e.result_sel := "110"; -- select NIA (to go to LR)
- when others =>
- end case;
+ -- DUPD is the only possibility here:
+ -- update-form loads, 2nd instruction writes RA
+ v.e.write_reg := dc2.e.read_reg1;
end if;
-- issue control
entity execute1 is
generic (
+ SIM : boolean := false;
EX1_BYPASS : boolean := true;
HAS_FPU : boolean := true;
HAS_SHORT_MULT : boolean := false;
dc_events : in DcacheEventType;
ic_events : in IcacheEventType;
+ -- debug
+ sim_dump : in std_ulogic;
+ sim_dump_done : out std_ulogic;
+
log_out : out std_ulogic_vector(14 downto 0);
log_rd_addr : out std_ulogic_vector(31 downto 0);
log_rd_data : in std_ulogic_vector(63 downto 0);
fp_intr : std_ulogic;
res2_sel : std_ulogic_vector(1 downto 0);
bypass_valid : std_ulogic;
+ ramspr_odd_data : std_ulogic_vector(63 downto 0);
end record;
constant actions_type_init : actions_type :=
(e => Execute1ToWritebackInit, se => side_effect_init,
- new_msr => (others => '0'), res2_sel => "00", others => '0');
+ new_msr => (others => '0'), res2_sel => "00",
+ ramspr_odd_data => 64x"0", others => '0');
type reg_stage1_type is record
e : Execute1ToWritebackType;
fp_exception_next : std_ulogic;
trace_next : std_ulogic;
prev_op : insn_type_t;
- br_taken : std_ulogic;
oe : std_ulogic;
mul_select : std_ulogic_vector(1 downto 0);
res2_sel : std_ulogic_vector(1 downto 0);
xerc : xer_common_t;
xerc_valid : std_ulogic;
ramspr_wraddr : ramspr_index;
+ ramspr_odd_data : std_ulogic_vector(63 downto 0);
end record;
constant reg_stage1_type_init : reg_stage1_type :=
(e => Execute1ToWritebackInit, se => side_effect_init,
busy => '0',
- fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL, br_taken => '0',
+ fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL,
oe => '0', mul_select => "00", res2_sel => "00",
spr_select => spr_id_init, pmu_spr_num => 5x"0",
mul_in_progress => '0', mul_finish => '0', div_in_progress => '0',
taken_branch_event => '0', br_mispredict => '0',
msr => 64x"0",
xerc => xerc_init, xerc_valid => '0',
- ramspr_wraddr => 0);
+ ramspr_wraddr => 0, ramspr_odd_data => 64x"0");
type reg_stage2_type is record
e : Execute1ToWritebackType;
odd_wr_data := intr_srr1(ctrl.msr, interrupt_in.srr1);
else
even_wr_data := ex1.e.write_data;
- odd_wr_data := ex1.e.write_data;
+ odd_wr_data := ex1.ramspr_odd_data;
end if;
ramspr_wr_addr <= wr_addr;
ramspr_even_wr_data <= even_wr_data;
ramspr_even <= even_rd_data;
end if;
if ex1.se.ramspr_write_odd = '1' and e_in.ramspr_odd_rdaddr = ex1.ramspr_wraddr then
- ramspr_odd <= ex1.e.write_data;
+ ramspr_odd <= ex1.ramspr_odd_data;
else
ramspr_odd <= odd_rd_data;
end if;
-- Data path for integer instructions (first execute stage)
execute1_dp: process(all)
variable a_inv : std_ulogic_vector(63 downto 0);
- variable b_or_m1 : std_ulogic_vector(63 downto 0);
variable sum_with_carry : std_ulogic_vector(64 downto 0);
variable sign1, sign2 : std_ulogic;
variable abs1, abs2 : signed(63 downto 0);
else
a_inv := not a_in;
end if;
- 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,
+ sum_with_carry := ppc_adde(a_inv, b_in,
decode_input_carry(e_in.input_carry, xerc_in));
adder_result <= sum_with_carry(63 downto 0);
carry_32 <= sum_with_carry(32) xor a_inv(32) xor b_in(32);
v.se.ramspr_write_even := e_in.ramspr_write_even;
v.se.ramspr_write_odd := e_in.ramspr_write_odd;
+ v.ramspr_odd_data := c_in;
+ if e_in.dec_ctr = '1' then
+ v.ramspr_odd_data := std_ulogic_vector(unsigned(ramspr_odd) - 1);
+ end if;
-- Note the difference between v.exception and v.trap:
-- v.exception signals a condition that prevents execution of the
end if;
v.se.write_cfar := '1';
when OP_BC =>
- -- read_data1 is CTR
- -- If this instruction updates both CTR and LR, then it is
- -- doubled; the first instruction decrements CTR and determines
- -- whether the branch is taken, and the second does the
- -- redirect and the LR update.
+ -- If CTR is being decremented, it is in ramspr_odd.
bo := insn_bo(e_in.insn);
bi := insn_bi(e_in.insn);
- if e_in.second = '0' then
- v.take_branch := ppc_bc_taken(bo, bi, cr_in, a_in);
- else
- v.take_branch := ex1.br_taken;
- end if;
+ v.take_branch := ppc_bc_taken(bo, bi, cr_in, ramspr_odd);
if v.take_branch = '1' then
v.e.br_offset := b_in;
v.e.abs_br := insn_aa(e_in.insn);
end if;
- if e_in.repeat = '0' or e_in.second = '1' then
- -- Mispredicted branches cause a redirect
- if v.take_branch /= e_in.br_pred then
- v.e.redirect := '1';
- end if;
- v.direct_branch := '1';
- v.e.br_last := '1';
- v.e.br_taken := v.take_branch;
- if ex1.msr(MSR_BE) = '1' then
- v.do_trace := '1';
- end if;
- v.se.write_cfar := v.take_branch;
+ -- Mispredicted branches cause a redirect
+ if v.take_branch /= e_in.br_pred then
+ v.e.redirect := '1';
+ end if;
+ v.direct_branch := '1';
+ v.e.br_last := '1';
+ v.e.br_taken := v.take_branch;
+ if ex1.msr(MSR_BE) = '1' then
+ v.do_trace := '1';
end if;
+ v.se.write_cfar := v.take_branch;
when OP_BCREG =>
- -- read_data1 is CTR, read_data2 is target register (CTR, LR or TAR)
- -- If this instruction updates both CTR and LR, then it is
- -- doubled; the first instruction decrements CTR and determines
- -- whether the branch is taken, and the second does the
- -- redirect and the LR update.
+ -- If CTR is being decremented, it is in ramspr_odd.
+ -- The target address is in ramspr_result (LR, CTR or TAR).
bo := insn_bo(e_in.insn);
bi := insn_bi(e_in.insn);
- if e_in.second = '0' then
- v.take_branch := ppc_bc_taken(bo, bi, cr_in, a_in);
- else
- v.take_branch := ex1.br_taken;
- end if;
+ v.take_branch := ppc_bc_taken(bo, bi, cr_in, ramspr_odd);
if v.take_branch = '1' then
- v.e.br_offset := b_in;
+ v.e.br_offset := ramspr_result;
v.e.abs_br := '1';
end if;
- if e_in.repeat = '0' or e_in.second = '1' then
- -- Indirect branches are never predicted taken
- v.e.redirect := v.take_branch;
- v.e.br_taken := v.take_branch;
- if ex1.msr(MSR_BE) = '1' then
- v.do_trace := '1';
- end if;
- v.se.write_cfar := v.take_branch;
+ -- Indirect branches are never predicted taken
+ v.e.redirect := v.take_branch;
+ v.e.br_taken := v.take_branch;
+ if ex1.msr(MSR_BE) = '1' then
+ v.do_trace := '1';
end if;
+ v.se.write_cfar := v.take_branch;
when OP_RFID =>
srr1 := ramspr_odd;
v.new_msr(MSR_DR) := '1';
end if;
v.se.write_msr := '1';
- v.e.br_offset := ramspr_even;
+ v.e.br_offset := ramspr_result;
v.e.abs_br := '1';
v.e.redirect := '1';
v.se.write_cfar := '1';
v.mul_select := e_in.sub_select(1 downto 0);
v.se := side_effect_init;
v.ramspr_wraddr := e_in.ramspr_wraddr;
+ v.ramspr_odd_data := actions.ramspr_odd_data;
end if;
lv := Execute1ToLoadstore1Init;
v.e.valid := actions.complete;
bypass_valid := actions.bypass_valid;
v.taken_branch_event := actions.take_branch;
- v.br_taken := actions.take_branch;
v.trace_next := actions.do_trace;
v.fp_exception_next := actions.fp_intr;
v.res2_sel := actions.res2_sel;
exception_log <= v.e.interrupt;
end process;
+ sim_dump_test: if SIM generate
+ dump_exregs: process(all)
+ variable xer : std_ulogic_vector(63 downto 0);
+ begin
+ if sim_dump = '1' then
+ report "LR " & to_hstring(even_sprs(RAMSPR_LR));
+ report "CTR " & to_hstring(odd_sprs(RAMSPR_CTR));
+ sim_dump_done <= '1';
+ else
+ sim_dump_done <= '0';
+ end if;
+ end process;
+ end generate;
+
+ -- Keep GHDL synthesis happy
+ sim_dump_test_synth: if not SIM generate
+ sim_dump_done <= '0';
+ end generate;
+
e1_log: if LOG_LENGTH > 0 generate
signal log_data : std_ulogic_vector(14 downto 0);
begin
loop_0: for i in 0 to 31 loop
report "GPR" & integer'image(i) & " " & to_hstring(registers(i));
end loop loop_0;
-
- report "LR " & to_hstring(registers(to_integer(unsigned(fast_spr_num(SPR_LR)))));
- report "CTR " & to_hstring(registers(to_integer(unsigned(fast_spr_num(SPR_CTR)))));
sim_dump_done <= '1';
else
sim_dump_done <= '0';