diff --git a/common.vhdl b/common.vhdl index 74341d1..7df451b 100644 --- a/common.vhdl +++ b/common.vhdl @@ -132,12 +132,15 @@ package common is 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; @@ -322,7 +325,6 @@ package common is 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; @@ -350,11 +352,12 @@ package common is 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', @@ -366,6 +369,7 @@ package common is 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 @@ -780,25 +784,8 @@ package body common is 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 diff --git a/core.vhdl b/core.vhdl index b2f2704..82c66b4 100644 --- a/core.vhdl +++ b/core.vhdl @@ -138,6 +138,7 @@ architecture behave of core 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 @@ -326,7 +327,7 @@ begin 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) ); @@ -347,6 +348,7 @@ begin execute1_0: entity work.execute1 generic map ( + SIM => SIM, EX1_BYPASS => EX1_BYPASS, HAS_FPU => HAS_FPU, HAS_SHORT_MULT => HAS_SHORT_MULT, @@ -376,6 +378,8 @@ begin 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, diff --git a/decode1.vhdl b/decode1.vhdl index fd01d61..b6cea31 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -89,8 +89,8 @@ architecture behaviour of decode1 is 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 @@ -177,7 +177,7 @@ architecture behaviour of decode1 is -- 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 @@ -530,6 +530,13 @@ architecture behaviour of decode1 is 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 => @@ -683,13 +690,6 @@ begin 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); @@ -698,37 +698,12 @@ begin -- 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 diff --git a/decode2.vhdl b/decode2.vhdl index c76b7f5..928ec94 100644 --- a/decode2.vhdl +++ b/decode2.vhdl @@ -406,6 +406,7 @@ begin 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; @@ -470,17 +471,45 @@ begin 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; @@ -520,7 +549,6 @@ begin 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; @@ -536,14 +564,6 @@ begin 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 @@ -562,16 +582,9 @@ begin -- 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 diff --git a/execute1.vhdl b/execute1.vhdl index b0b2f98..5ee830b 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -12,6 +12,7 @@ use work.ppc_fx_insns.all; entity execute1 is generic ( + SIM : boolean := false; EX1_BYPASS : boolean := true; HAS_FPU : boolean := true; HAS_SHORT_MULT : boolean := false; @@ -54,6 +55,10 @@ entity execute1 is 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); @@ -92,10 +97,12 @@ architecture behaviour of execute1 is 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; @@ -104,7 +111,6 @@ architecture behaviour of execute1 is 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); @@ -122,11 +128,12 @@ architecture behaviour of execute1 is 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', @@ -134,7 +141,7 @@ architecture behaviour of execute1 is 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; @@ -514,7 +521,7 @@ begin 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; @@ -531,7 +538,7 @@ begin 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; @@ -600,7 +607,6 @@ begin -- 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); @@ -635,12 +641,7 @@ begin 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); @@ -956,6 +957,10 @@ begin 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 @@ -1059,61 +1064,42 @@ begin 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; @@ -1130,7 +1116,7 @@ begin 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'; @@ -1343,6 +1329,7 @@ begin 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; @@ -1430,7 +1417,6 @@ begin 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; @@ -1759,6 +1745,25 @@ begin 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 diff --git a/register_file.vhdl b/register_file.vhdl index 0235dfc..ed856cb 100644 --- a/register_file.vhdl +++ b/register_file.vhdl @@ -130,9 +130,6 @@ 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';