core: Move redirect and interrupt delivery logic to writeback

This moves the logic for redirecting fetching and writing SRR0 and
SRR1 to writeback.  The aim is that ultimately units other than
execute1 can send their interrupts to writeback along with their
instruction completions, so that there can be multiple instructions
in flight without needing execute1 to keep track of the address
of each outstanding instruction.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/269/head
Paul Mackerras 3 years ago
parent 4fd8d9509c
commit 3cd3449b4b

@ -139,8 +139,6 @@ package common is
constant instr_tag_init : instr_tag_t := (tag => 0, valid => '0');
function tag_match(tag1 : instr_tag_t; tag2 : instr_tag_t) return boolean;

type irq_state_t is (WRITE_SRR0, WRITE_SRR1);

-- For now, fixed 16 sources, make this either a parametric
-- package of some sort or an unconstrainted array.
type ics_to_icp_t is record
@ -157,8 +155,6 @@ package common is
dec: std_ulogic_vector(63 downto 0);
msr: std_ulogic_vector(63 downto 0);
cfar: std_ulogic_vector(63 downto 0);
irq_state : irq_state_t;
srr1: std_ulogic_vector(63 downto 0);
end record;

type Fetch1ToIcacheType is record
@ -329,22 +325,6 @@ package common is
read_xerc_data : xer_common_t;
end record;

type Execute1ToFetch1Type is record
redirect: std_ulogic;
virt_mode: std_ulogic;
priv_mode: std_ulogic;
big_endian: std_ulogic;
mode_32bit: std_ulogic;
redirect_nia: std_ulogic_vector(63 downto 0);
br_nia : std_ulogic_vector(63 downto 0);
br_last : std_ulogic;
br_taken : std_ulogic;
end record;
constant Execute1ToFetch1Init : Execute1ToFetch1Type := (redirect => '0', virt_mode => '0',
priv_mode => '0', big_endian => '0',
mode_32bit => '0', br_taken => '0',
br_last => '0', others => (others => '0'));

type Execute1ToLoadstore1Type is record
valid : std_ulogic;
op : insn_type_t; -- what ld/st or m[tf]spr or TLB op to do
@ -492,17 +472,26 @@ package common is
write_cr_data : std_ulogic_vector(31 downto 0);
write_xerc_enable : std_ulogic;
xerc : xer_common_t;
exc_write_enable : std_ulogic;
exc_write_reg : gspr_index_t;
exc_write_data : std_ulogic_vector(63 downto 0);
interrupt : std_ulogic;
intr_vec : integer range 0 to 16#fff#;
redirect: std_ulogic;
redir_mode: std_ulogic_vector(3 downto 0);
last_nia: std_ulogic_vector(63 downto 0);
br_offset: std_ulogic_vector(63 downto 0);
br_last: std_ulogic;
br_taken: std_ulogic;
abs_br: std_ulogic;
srr1: std_ulogic_vector(63 downto 0);
end record;
constant Execute1ToWritebackInit : Execute1ToWritebackType :=
(valid => '0', instr_tag => instr_tag_init, rc => '0', mode_32bit => '0',
write_enable => '0', write_cr_enable => '0', exc_write_enable => '0',
write_enable => '0', write_cr_enable => '0',
write_xerc_enable => '0', xerc => xerc_init,
write_data => (others => '0'), write_cr_mask => (others => '0'),
write_cr_data => (others => '0'), write_reg => (others => '0'),
exc_write_reg => (others => '0'), exc_write_data => (others => '0'));
interrupt => '0', intr_vec => 0, redirect => '0', redir_mode => "0000",
last_nia => (others => '0'), br_offset => (others => '0'),
br_last => '0', br_taken => '0', abs_br => '0', srr1 => (others => '0'));

type Execute1ToFPUType is record
valid : std_ulogic;
@ -556,6 +545,22 @@ package common is
constant DividerToExecute1Init : DividerToExecute1Type := (valid => '0', overflow => '0',
others => (others => '0'));

type WritebackToFetch1Type is record
redirect: std_ulogic;
virt_mode: std_ulogic;
priv_mode: std_ulogic;
big_endian: std_ulogic;
mode_32bit: std_ulogic;
redirect_nia: std_ulogic_vector(63 downto 0);
br_nia : std_ulogic_vector(63 downto 0);
br_last : std_ulogic;
br_taken : std_ulogic;
end record;
constant WritebackToFetch1Init : WritebackToFetch1Type :=
(redirect => '0', virt_mode => '0', priv_mode => '0', big_endian => '0',
mode_32bit => '0', redirect_nia => (others => '0'),
br_last => '0', br_taken => '0', br_nia => (others => '0'));

type WritebackToRegisterFileType is record
write_reg : gspr_index_t;
write_data : std_ulogic_vector(63 downto 0);

@ -235,8 +235,7 @@ begin
stall_tmp := '0';

if flush_in = '1' then
-- expect to see complete_in next cycle
v_int.outstanding := 1;
v_int.outstanding := 0;
elsif complete_in.valid = '1' then
v_int.outstanding := r_int.outstanding - 1;
end if;

@ -46,6 +46,7 @@ end core;
architecture behave of core is
-- icache signals
signal fetch1_to_icache : Fetch1ToIcacheType;
signal writeback_to_fetch1: WritebackToFetch1Type;
signal icache_to_decode1 : IcacheToDecode1Type;
signal mmu_to_icache : MmuToIcacheType;

@ -66,7 +67,6 @@ architecture behave of core is

-- execute signals
signal execute1_to_writeback: Execute1ToWritebackType;
signal execute1_to_fetch1: Execute1ToFetch1Type;
signal execute1_bypass: bypass_data_t;
signal execute1_cr_bypass: cr_bypass_data_t;

@ -108,6 +108,7 @@ architecture behave of core is
signal terminate: std_ulogic;
signal core_rst: std_ulogic;
signal icache_inv: std_ulogic;
signal do_interrupt: std_ulogic;

-- Delayed/Latched resets and alt_reset
signal rst_fetch1 : std_ulogic := '1';
@ -119,6 +120,7 @@ architecture behave of core is
signal rst_ex1 : std_ulogic := '1';
signal rst_fpu : std_ulogic := '1';
signal rst_ls1 : std_ulogic := '1';
signal rst_wback : std_ulogic := '1';
signal rst_dbg : std_ulogic := '1';
signal alt_reset_d : std_ulogic;

@ -182,6 +184,7 @@ begin
rst_ex1 <= core_rst;
rst_fpu <= core_rst;
rst_ls1 <= core_rst;
rst_wback <= core_rst;
rst_dbg <= rst;
alt_reset_d <= alt_reset;
end if;
@ -202,7 +205,7 @@ begin
inval_btc => ex1_icache_inval or mmu_to_icache.tlbie,
stop_in => dbg_core_stop,
d_in => decode1_to_fetch1,
e_in => execute1_to_fetch1,
w_in => writeback_to_fetch1,
i_out => fetch1_to_icache,
log_out => log_data(42 downto 0)
);
@ -324,14 +327,14 @@ begin
port map (
clk => clk,
rst => rst_ex1,
flush_out => flush,
flush_in => flush,
busy_out => ex1_busy_out,
e_in => decode2_to_execute1,
l_in => loadstore1_to_execute1,
fp_in => fpu_to_execute1,
ext_irq_in => ext_irq,
interrupt_in => do_interrupt,
l_out => execute1_to_loadstore1,
f_out => execute1_to_fetch1,
fp_out => execute1_to_fpu,
e_out => execute1_to_writeback,
bypass_data => execute1_bypass,
@ -416,11 +419,15 @@ begin
writeback_0: entity work.writeback
port map (
clk => clk,
rst => rst_wback,
flush_out => flush,
e_in => execute1_to_writeback,
l_in => loadstore1_to_writeback,
fp_in => fpu_to_writeback,
w_out => writeback_to_register_file,
c_out => writeback_to_cr_file,
f_out => writeback_to_fetch1,
interrupt_out => do_interrupt,
complete_out => complete
);


@ -22,7 +22,7 @@ entity execute1 is
rst : in std_ulogic;

-- asynchronous
flush_out : out std_ulogic;
flush_in : in std_ulogic;
busy_out : out std_ulogic;

e_in : in Decode2ToExecute1Type;
@ -30,10 +30,10 @@ entity execute1 is
fp_in : in FPUToExecute1Type;

ext_irq_in : std_ulogic;
interrupt_in : std_ulogic;

-- asynchronous
l_out : out Execute1ToLoadstore1Type;
f_out : out Execute1ToFetch1Type;
fp_out : out Execute1ToFPUType;

e_out : out Execute1ToWritebackType;
@ -61,21 +61,11 @@ architecture behaviour of execute1 is
fp_exception_next : std_ulogic;
trace_next : std_ulogic;
prev_op : insn_type_t;
next_lr : std_ulogic_vector(63 downto 0);
br_taken : std_ulogic;
mul_in_progress : std_ulogic;
mul_finish : std_ulogic;
div_in_progress : std_ulogic;
cntz_in_progress : std_ulogic;
last_nia : std_ulogic_vector(63 downto 0);
redirect : std_ulogic;
abs_br : std_ulogic;
taken_br : std_ulogic;
br_last : std_ulogic;
do_intr : std_ulogic;
vector : integer range 0 to 16#fff#;
br_offset : std_ulogic_vector(63 downto 0);
redir_mode : std_ulogic_vector(3 downto 0);
log_addr_spr : std_ulogic_vector(31 downto 0);
end record;
constant reg_type_init : reg_type :=
@ -84,9 +74,6 @@ architecture behaviour of execute1 is
busy => '0', terminate => '0',
fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL, br_taken => '0',
mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', cntz_in_progress => '0',
next_lr => (others => '0'), last_nia => (others => '0'),
redirect => '0', abs_br => '0', taken_br => '0', br_last => '0', do_intr => '0', vector => 0,
br_offset => (others => '0'), redir_mode => "0000",
others => (others => '0'));

signal r, rin : reg_type;
@ -96,8 +83,8 @@ architecture behaviour of execute1 is
signal xerc_in : xer_common_t;

signal valid_in : std_ulogic;
signal ctrl: ctrl_t := (irq_state => WRITE_SRR0, others => (others => '0'));
signal ctrl_tmp: ctrl_t := (irq_state => WRITE_SRR0, others => (others => '0'));
signal ctrl: ctrl_t := (others => (others => '0'));
signal ctrl_tmp: ctrl_t := (others => (others => '0'));
signal right_shift, rot_clear_left, rot_clear_right: std_ulogic;
signal rot_sign_ext: std_ulogic;
signal rotator_result: std_ulogic_vector(63 downto 0);
@ -307,7 +294,7 @@ begin
xerc_in <= r.e.xerc when r.e.write_xerc_enable = '1' or r.busy = '1' else e_in.xerc;

busy_out <= l_in.busy or r.busy or fp_in.busy;
valid_in <= e_in.valid and not busy_out;
valid_in <= e_in.valid and not busy_out and not flush_in;

terminate_out <= r.terminate;

@ -332,7 +319,6 @@ begin
ctrl.tb <= (others => '0');
ctrl.dec <= (others => '0');
ctrl.msr <= (MSR_SF => '1', MSR_LE => '1', others => '0');
ctrl.irq_state <= WRITE_SRR0;
else
r <= rin;
ctrl <= ctrl_tmp;
@ -673,7 +659,6 @@ begin
variable lv : Execute1ToLoadstore1Type;
variable irq_valid : std_ulogic;
variable exception : std_ulogic;
variable exception_nextpc : std_ulogic;
variable illegal : std_ulogic;
variable is_branch : std_ulogic;
variable is_direct_branch : std_ulogic;
@ -682,7 +667,6 @@ begin
variable spr_val : std_ulogic_vector(63 downto 0);
variable do_trace : std_ulogic;
variable hold_wr_data : std_ulogic;
variable f : Execute1ToFetch1Type;
variable fv : Execute1ToFPUType;
begin
is_branch := '0';
@ -693,15 +677,8 @@ begin

v := r;
v.e := Execute1ToWritebackInit;
v.redirect := '0';
v.abs_br := '0';
v.do_intr := '0';
v.vector := 0;
v.br_offset := (others => '0');
v.redir_mode := ctrl.msr(MSR_IR) & not ctrl.msr(MSR_PR) &
not ctrl.msr(MSR_LE) & not ctrl.msr(MSR_SF);
v.taken_br := '0';
v.br_last := '0';
v.e.redir_mode := ctrl.msr(MSR_IR) & not ctrl.msr(MSR_PR) &
not ctrl.msr(MSR_LE) & not ctrl.msr(MSR_SF);
v.e.xerc := xerc_in;

lv := Execute1ToLoadstore1Init;
@ -725,11 +702,11 @@ begin
irq_valid := '0';
if ctrl.msr(MSR_EE) = '1' then
if ctrl.dec(63) = '1' then
v.vector := 16#900#;
v.e.intr_vec := 16#900#;
report "IRQ valid: DEC";
irq_valid := '1';
elsif ext_irq_in = '1' then
v.vector := 16#500#;
v.e.intr_vec := 16#500#;
report "IRQ valid: External";
irq_valid := '1';
end if;
@ -748,18 +725,13 @@ begin
rot_clear_right <= '1' when e_in.insn_type = OP_RLC or e_in.insn_type = OP_RLCR else '0';
rot_sign_ext <= '1' when e_in.insn_type = OP_EXTSWSLI else '0';

ctrl_tmp.srr1 <= msr_copy(ctrl.msr);
ctrl_tmp.irq_state <= WRITE_SRR0;
v.e.srr1 := msr_copy(ctrl.msr);
exception := '0';
illegal := '0';
exception_nextpc := '0';
v.e.exc_write_enable := '0';
v.e.exc_write_reg := fast_spr_num(SPR_SRR0);
if valid_in = '1' then
v.e.exc_write_data := e_in.nia;
v.last_nia := e_in.nia;
v.e.last_nia := e_in.nia;
else
v.e.exc_write_data := r.last_nia;
v.e.last_nia := r.e.last_nia;
end if;

v.e.mode_32bit := not ctrl.msr(MSR_SF);
@ -777,20 +749,20 @@ begin
-- This is used for FP-type program interrupts that
-- become pending due to MSR[FE0,FE1] changing from 00 to non-zero.
exception := '1';
v.vector := 16#700#;
ctrl_tmp.srr1(63 - 43) <= '1';
ctrl_tmp.srr1(63 - 47) <= '1';
v.e.intr_vec := 16#700#;
v.e.srr1(63 - 43) := '1';
v.e.srr1(63 - 47) := '1';
elsif r.trace_next = '1' then
-- Generate a trace interrupt rather than executing the next instruction
-- or taking any asynchronous interrupt
exception := '1';
v.vector := 16#d00#;
ctrl_tmp.srr1(63 - 33) <= '1';
v.e.intr_vec := 16#d00#;
v.e.srr1(63 - 33) := '1';
if r.prev_op = OP_LOAD or r.prev_op = OP_ICBI or r.prev_op = OP_ICBT or
r.prev_op = OP_DCBT or r.prev_op = OP_DCBST or r.prev_op = OP_DCBF then
ctrl_tmp.srr1(63 - 35) <= '1';
v.e.srr1(63 - 35) := '1';
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';
v.e.srr1(63 - 36) := '1';
end if;

elsif irq_valid = '1' then
@ -801,9 +773,9 @@ begin
elsif ctrl.msr(MSR_PR) = '1' and instr_is_privileged(e_in.insn_type, e_in.insn) then
-- generate a program interrupt
exception := '1';
v.vector := 16#700#;
v.e.intr_vec := 16#700#;
-- set bit 45 to indicate privileged instruction type interrupt
ctrl_tmp.srr1(63 - 45) <= '1';
v.e.srr1(63 - 45) := '1';
report "privileged instruction";

elsif not HAS_FPU and e_in.fac = FPU then
@ -813,14 +785,13 @@ begin
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#;
v.e.intr_vec := 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
v.cur_instr := e_in;
v.next_lr := next_nia;
v.e.valid := '1';

case_0: case e_in.insn_type is
@ -835,8 +806,8 @@ begin
-- we need two cycles to write srr0 and 1
if e_in.insn(1) = '1' then
exception := '1';
exception_nextpc := '1';
v.vector := 16#C00#;
v.e.intr_vec := 16#C00#;
v.e.last_nia := next_nia;
report "sc";
else
illegal := '1';
@ -867,9 +838,9 @@ begin
when OP_CMP =>
when OP_TRAP =>
-- trap instructions (tw, twi, td, tdi)
v.vector := 16#700#;
v.e.intr_vec := 16#700#;
-- set bit 46 to say trap occurred
ctrl_tmp.srr1(63 - 46) <= '1';
v.e.srr1(63 - 46) := '1';
if or (trapval and insn_to(e_in.insn)) = '1' then
-- generate trap-type program interrupt
exception := '1';
@ -916,8 +887,8 @@ begin
end if;

when OP_RFID =>
v.redir_mode := (a_in(MSR_IR) or a_in(MSR_PR)) & not a_in(MSR_PR) &
not a_in(MSR_LE) & not a_in(MSR_SF);
v.e.redir_mode := (a_in(MSR_IR) or a_in(MSR_PR)) & not a_in(MSR_PR) &
not a_in(MSR_LE) & not a_in(MSR_SF);
-- Can't use msr_copy here because the partial function MSR
-- bits should be left unchanged, not zeroed.
ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31);
@ -1051,8 +1022,8 @@ begin
when OP_SETB =>

when OP_ISYNC =>
v.redirect := '1';
v.br_offset := std_ulogic_vector(to_unsigned(4, 64));
v.e.redirect := '1';
v.e.br_offset := std_ulogic_vector(to_unsigned(4, 64));

when OP_ICBI =>
icache_inval <= '1';
@ -1080,16 +1051,16 @@ begin
ctrl_tmp.cfar <= e_in.nia;
end if;
if taken_branch = '1' then
v.br_offset := b_in;
v.abs_br := abs_branch;
v.e.br_offset := b_in;
v.e.abs_br := abs_branch;
else
v.br_offset := std_ulogic_vector(to_unsigned(4, 64));
v.e.br_offset := std_ulogic_vector(to_unsigned(4, 64));
end if;
if taken_branch /= e_in.br_pred then
v.redirect := '1';
v.e.redirect := '1';
end if;
v.br_last := is_direct_branch;
v.taken_br := taken_branch;
v.e.br_last := is_direct_branch;
v.e.br_taken := taken_branch;
end if;

elsif valid_in = '1' and exception = '0' and illegal = '0' then
@ -1110,28 +1081,7 @@ begin
-- The following cases all occur when r.busy = 1 and therefore
-- valid_in = 0. Hence they don't happen in the same cycle as any of
-- the cases above which depend on valid_in = 1.

if ctrl.irq_state = WRITE_SRR1 then
v.e.exc_write_reg := fast_spr_num(SPR_SRR1);
v.e.exc_write_data := ctrl.srr1;
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.trace_next := '0';
v.fp_exception_next := '0';
report "Writing SRR1: " & to_hstring(ctrl.srr1);

elsif r.cntz_in_progress = '1' then
if r.cntz_in_progress = '1' then
-- cnt[lt]z always takes two cycles
v.e.valid := '1';
elsif r.mul_in_progress = '1' or r.div_in_progress = '1' then
@ -1179,63 +1129,67 @@ begin
-- The case where MSR[FE0,FE1] goes from zero to non-zero is
-- handled above by mtmsrd and rfid setting v.fp_exception_next.
if HAS_FPU and fp_in.interrupt = '1' then
v.vector := 16#700#;
ctrl_tmp.srr1(63 - 43) <= '1';
v.e.intr_vec := 16#700#;
v.e.srr1(63 - 43) := '1';
exception := '1';
end if;

if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then
exception := '1';
v.vector := 16#700#;
v.e.intr_vec := 16#700#;
-- Since we aren't doing Hypervisor emulation assist (0xe40) we
-- set bit 44 to indicate we have an illegal
ctrl_tmp.srr1(63 - 44) <= '1';
v.e.srr1(63 - 44) := '1';
report "illegal";
end if;
if exception = '1' then
v.e.exc_write_enable := '1';
if exception_nextpc = '1' then
v.e.exc_write_data := next_nia;
end if;
end if;

-- generate DSI or DSegI for load/store exceptions
-- or ISI or ISegI for instruction fetch exceptions
if l_in.exception = '1' then
if l_in.alignment = '1' then
v.vector := 16#600#;
v.e.intr_vec := 16#600#;
elsif l_in.instr_fault = '0' then
if l_in.segment_fault = '0' then
v.vector := 16#300#;
v.e.intr_vec := 16#300#;
else
v.vector := 16#380#;
v.e.intr_vec := 16#380#;
end if;
else
if l_in.segment_fault = '0' then
ctrl_tmp.srr1(63 - 33) <= l_in.invalid;
ctrl_tmp.srr1(63 - 35) <= l_in.perm_error; -- noexec fault
ctrl_tmp.srr1(63 - 44) <= l_in.badtree;
ctrl_tmp.srr1(63 - 45) <= l_in.rc_error;
v.vector := 16#400#;
v.e.srr1(63 - 33) := l_in.invalid;
v.e.srr1(63 - 35) := l_in.perm_error; -- noexec fault
v.e.srr1(63 - 44) := l_in.badtree;
v.e.srr1(63 - 45) := l_in.rc_error;
v.e.intr_vec := 16#400#;
else
v.vector := 16#480#;
v.e.intr_vec := 16#480#;
end if;
end if;
v.e.exc_write_enable := '1';
v.e.exc_write_reg := fast_spr_num(SPR_SRR0);
report "ldst exception writing srr0=" & to_hstring(r.last_nia);
end if;

if exception = '1' or l_in.exception = '1' then
ctrl_tmp.irq_state <= WRITE_SRR1;
v.redirect := '1';
v.do_intr := '1';
end if;
v.e.interrupt := exception or l_in.exception;

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

if interrupt_in = '1' then
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.trace_next := '0';
v.fp_exception_next := '0';
end if;

if hold_wr_data = '0' then
v.e.write_data := alu_result;
else
@ -1263,41 +1217,6 @@ begin
end if;
end loop;

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

-- Outputs to fetch1
f.redirect := r.redirect;
f.br_nia := r.last_nia;
f.br_last := r.br_last and not r.do_intr;
f.br_taken := r.taken_br;
if r.do_intr = '1' then
f.redirect_nia := std_ulogic_vector(to_unsigned(r.vector, 64));
f.virt_mode := '0';
f.priv_mode := '1';
-- XXX need an interrupt LE bit here, e.g. from LPCR
f.big_endian := '0';
f.mode_32bit := '0';
else
if r.abs_br = '1' then
f.redirect_nia := r.br_offset;
else
f.redirect_nia := std_ulogic_vector(unsigned(r.last_nia) + unsigned(r.br_offset));
end if;
-- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1
f.virt_mode := r.redir_mode(3);
f.priv_mode := r.redir_mode(2);
f.big_endian := r.redir_mode(1);
f.mode_32bit := r.redir_mode(0);
end if;

-- Outputs to loadstore1 (async)
lv.op := e_in.insn_type;
lv.nia := e_in.nia;
@ -1344,11 +1263,9 @@ begin
rin <= v;

-- update outputs
f_out <= f;
l_out <= lv;
e_out <= r.e;
fp_out <= fv;
flush_out <= f_out.redirect;

exception_log <= exception;
irq_valid_log <= irq_valid;
@ -1364,13 +1281,13 @@ begin
ctrl.msr(MSR_IR) & ctrl.msr(MSR_DR) &
exception_log &
irq_valid_log &
std_ulogic_vector(to_unsigned(irq_state_t'pos(ctrl.irq_state), 1)) &
interrupt_in &
"000" &
r.e.write_enable &
r.e.valid &
f_out.redirect &
(r.e.redirect or r.e.interrupt) &
r.busy &
flush_out;
flush_in;
end if;
end process;
log_out <= log_data;

@ -22,8 +22,8 @@ entity fetch1 is
stop_in : in std_ulogic;
alt_reset_in : in std_ulogic;

-- redirect from execution unit
e_in : in Execute1ToFetch1Type;
-- redirect from writeback unit
w_in : in WritebackToFetch1Type;

-- redirect from decode1
d_in : in Decode1ToFetch1Type;
@ -70,12 +70,12 @@ begin
" P:" & std_ulogic'image(r_next.priv_mode) &
" E:" & std_ulogic'image(r_next.big_endian) &
" 32:" & std_ulogic'image(r_next_int.mode_32bit) &
" R:" & std_ulogic'image(e_in.redirect) & std_ulogic'image(d_in.redirect) &
" R:" & std_ulogic'image(w_in.redirect) & std_ulogic'image(d_in.redirect) &
" S:" & std_ulogic'image(stall_in) &
" T:" & std_ulogic'image(stop_in) &
" nia:" & to_hstring(r_next.nia);
end if;
if rst = '1' or e_in.redirect = '1' or d_in.redirect = '1' or stall_in = '0' then
if rst = '1' or w_in.redirect = '1' or d_in.redirect = '1' or stall_in = '0' then
r.virt_mode <= r_next.virt_mode;
r.priv_mode <= r_next.priv_mode;
r.big_endian <= r_next.big_endian;
@ -109,11 +109,11 @@ begin
signal btc_wr_addr : std_ulogic_vector(BTC_ADDR_BITS - 1 downto 0);
signal btc_wr_v : std_ulogic;
begin
btc_wr_data <= e_in.br_nia(63 downto BTC_ADDR_BITS + 2) &
e_in.redirect_nia(63 downto 2);
btc_wr_addr <= e_in.br_nia(BTC_ADDR_BITS + 1 downto 2);
btc_wr <= e_in.br_last;
btc_wr_v <= e_in.br_taken;
btc_wr_data <= w_in.br_nia(63 downto BTC_ADDR_BITS + 2) &
w_in.redirect_nia(63 downto 2);
btc_wr_addr <= w_in.br_nia(BTC_ADDR_BITS + 1 downto 2);
btc_wr <= w_in.br_last;
btc_wr_v <= w_in.br_taken;

btc_ram : process(clk)
variable raddr : unsigned(BTC_ADDR_BITS - 1 downto 0);
@ -158,15 +158,15 @@ begin
v.big_endian := '0';
v_int.mode_32bit := '0';
v_int.predicted_nia := (others => '0');
elsif e_in.redirect = '1' then
v.nia := e_in.redirect_nia(63 downto 2) & "00";
if e_in.mode_32bit = '1' then
elsif w_in.redirect = '1' then
v.nia := w_in.redirect_nia(63 downto 2) & "00";
if w_in.mode_32bit = '1' then
v.nia(63 downto 32) := (others => '0');
end if;
v.virt_mode := e_in.virt_mode;
v.priv_mode := e_in.priv_mode;
v.big_endian := e_in.big_endian;
v_int.mode_32bit := e_in.mode_32bit;
v.virt_mode := w_in.virt_mode;
v.priv_mode := w_in.priv_mode;
v.big_endian := w_in.big_endian;
v_int.mode_32bit := w_in.mode_32bit;
elsif d_in.redirect = '1' then
v.nia := d_in.redirect_nia(63 downto 2) & "00";
if r_int.mode_32bit = '1' then
@ -191,7 +191,7 @@ begin

-- If the last NIA value went down with a stop mark, it didn't get
-- executed, and hence we shouldn't increment NIA.
advance_nia <= rst or e_in.redirect or d_in.redirect or (not r.stop_mark and not stall_in);
advance_nia <= rst or w_in.redirect or d_in.redirect or (not r.stop_mark and not stall_in);

r_next <= v;
r_next_int <= v_int;

@ -9,6 +9,7 @@ use work.crhelpers.all;
entity writeback is
port (
clk : in std_ulogic;
rst : in std_ulogic;

e_in : in Execute1ToWritebackType;
l_in : in Loadstore1ToWritebackType;
@ -16,12 +17,24 @@ entity writeback is

w_out : out WritebackToRegisterFileType;
c_out : out WritebackToCrFileType;
f_out : out WritebackToFetch1Type;

flush_out : out std_ulogic;
interrupt_out: out std_ulogic;
complete_out : out instr_tag_t
);
end entity writeback;

architecture behaviour of writeback is
type irq_state_t is (WRITE_SRR0, WRITE_SRR1);

type reg_type is record
state : irq_state_t;
srr1 : std_ulogic_vector(63 downto 0);
end record;

signal r, rin : reg_type;

begin
writeback_0: process(clk)
variable x : std_ulogic_vector(0 downto 0);
@ -29,6 +42,13 @@ begin
variable w : std_ulogic_vector(0 downto 0);
begin
if rising_edge(clk) then
if rst = '1' then
r.state <= WRITE_SRR0;
r.srr1 <= (others => '0');
else
r <= rin;
end if;

-- Do consistency checks only on the clock edge
x(0) := e_in.valid;
y(0) := l_in.valid;
@ -36,7 +56,7 @@ begin
assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
to_integer(unsigned(w))) <= 1 severity failure;

x(0) := e_in.write_enable or e_in.exc_write_enable;
x(0) := e_in.write_enable;
y(0) := l_in.write_enable;
w(0) := fp_in.write_enable;
assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
@ -55,6 +75,8 @@ begin
end process;

writeback_1: process(all)
variable v : reg_type;
variable f : WritebackToFetch1Type;
variable cf: std_ulogic_vector(3 downto 0);
variable zero : std_ulogic;
variable sign : std_ulogic;
@ -62,6 +84,9 @@ begin
begin
w_out <= WritebackToRegisterFileInit;
c_out <= WritebackToCrFileInit;
f := WritebackToFetch1Init;
interrupt_out <= '0';
v := r;

complete_out <= instr_tag_init;
if e_in.valid = '1' then
@ -72,10 +97,19 @@ begin
complete_out <= fp_in.instr_tag;
end if;

if e_in.exc_write_enable = '1' then
w_out.write_reg <= e_in.exc_write_reg;
w_out.write_data <= e_in.exc_write_data;
if r.state = WRITE_SRR1 then
w_out.write_reg <= fast_spr_num(SPR_SRR1);
w_out.write_data <= r.srr1;
w_out.write_enable <= '1';
interrupt_out <= '1';
v.state := WRITE_SRR0;

elsif e_in.interrupt = '1' then
w_out.write_reg <= fast_spr_num(SPR_SRR0);
w_out.write_data <= e_in.last_nia;
w_out.write_enable <= '1';
v.state := WRITE_SRR1;
v.srr1 := e_in.srr1;
else
if e_in.write_enable = '1' then
w_out.write_reg <= e_in.write_reg;
@ -142,5 +176,35 @@ begin
c_out.write_cr_data(31 downto 28) <= cf;
end if;
end if;

-- Outputs to fetch1
f.redirect := e_in.redirect or e_in.interrupt;
f.br_nia := e_in.last_nia;
f.br_last := e_in.br_last and not e_in.interrupt;
f.br_taken := e_in.br_taken;
if e_in.interrupt = '1' then
f.redirect_nia := std_ulogic_vector(to_unsigned(e_in.intr_vec, 64));
f.virt_mode := '0';
f.priv_mode := '1';
-- XXX need an interrupt LE bit here, e.g. from LPCR
f.big_endian := '0';
f.mode_32bit := '0';
else
if e_in.abs_br = '1' then
f.redirect_nia := e_in.br_offset;
else
f.redirect_nia := std_ulogic_vector(unsigned(e_in.last_nia) + unsigned(e_in.br_offset));
end if;
-- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1
f.virt_mode := e_in.redir_mode(3);
f.priv_mode := e_in.redir_mode(2);
f.big_endian := e_in.redir_mode(1);
f.mode_32bit := e_in.redir_mode(0);
end if;

f_out <= f;
flush_out <= f_out.redirect;

rin <= v;
end process;
end;

Loading…
Cancel
Save