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 4 years ago
parent 4fd8d9509c
commit 3cd3449b4b

@ -139,8 +139,6 @@ package common is
constant instr_tag_init : instr_tag_t := (tag => 0, valid => '0'); constant instr_tag_init : instr_tag_t := (tag => 0, valid => '0');
function tag_match(tag1 : instr_tag_t; tag2 : instr_tag_t) return boolean; 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 -- For now, fixed 16 sources, make this either a parametric
-- package of some sort or an unconstrainted array. -- package of some sort or an unconstrainted array.
type ics_to_icp_t is record type ics_to_icp_t is record
@ -157,8 +155,6 @@ package common is
dec: std_ulogic_vector(63 downto 0); dec: std_ulogic_vector(63 downto 0);
msr: std_ulogic_vector(63 downto 0); msr: std_ulogic_vector(63 downto 0);
cfar: 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; end record;


type Fetch1ToIcacheType is record type Fetch1ToIcacheType is record
@ -329,22 +325,6 @@ package common is
read_xerc_data : xer_common_t; read_xerc_data : xer_common_t;
end record; 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 type Execute1ToLoadstore1Type is record
valid : std_ulogic; valid : std_ulogic;
op : insn_type_t; -- what ld/st or m[tf]spr or TLB op to do 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_cr_data : std_ulogic_vector(31 downto 0);
write_xerc_enable : std_ulogic; write_xerc_enable : std_ulogic;
xerc : xer_common_t; xerc : xer_common_t;
exc_write_enable : std_ulogic; interrupt : std_ulogic;
exc_write_reg : gspr_index_t; intr_vec : integer range 0 to 16#fff#;
exc_write_data : std_ulogic_vector(63 downto 0); 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; end record;
constant Execute1ToWritebackInit : Execute1ToWritebackType := constant Execute1ToWritebackInit : Execute1ToWritebackType :=
(valid => '0', instr_tag => instr_tag_init, rc => '0', mode_32bit => '0', (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_xerc_enable => '0', xerc => xerc_init,
write_data => (others => '0'), write_cr_mask => (others => '0'), write_data => (others => '0'), write_cr_mask => (others => '0'),
write_cr_data => (others => '0'), write_reg => (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 type Execute1ToFPUType is record
valid : std_ulogic; valid : std_ulogic;
@ -556,6 +545,22 @@ package common is
constant DividerToExecute1Init : DividerToExecute1Type := (valid => '0', overflow => '0', constant DividerToExecute1Init : DividerToExecute1Type := (valid => '0', overflow => '0',
others => (others => '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 type WritebackToRegisterFileType is record
write_reg : gspr_index_t; write_reg : gspr_index_t;
write_data : std_ulogic_vector(63 downto 0); write_data : std_ulogic_vector(63 downto 0);

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


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

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


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


-- execute signals -- execute signals
signal execute1_to_writeback: Execute1ToWritebackType; signal execute1_to_writeback: Execute1ToWritebackType;
signal execute1_to_fetch1: Execute1ToFetch1Type;
signal execute1_bypass: bypass_data_t; signal execute1_bypass: bypass_data_t;
signal execute1_cr_bypass: cr_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 terminate: std_ulogic;
signal core_rst: std_ulogic; signal core_rst: std_ulogic;
signal icache_inv: std_ulogic; signal icache_inv: std_ulogic;
signal do_interrupt: std_ulogic;


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


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



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


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


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


ext_irq_in : std_ulogic; ext_irq_in : std_ulogic;
interrupt_in : std_ulogic;


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


e_out : out Execute1ToWritebackType; e_out : out Execute1ToWritebackType;
@ -61,21 +61,11 @@ architecture behaviour of execute1 is
fp_exception_next : std_ulogic; fp_exception_next : std_ulogic;
trace_next : std_ulogic; trace_next : std_ulogic;
prev_op : insn_type_t; prev_op : insn_type_t;
next_lr : std_ulogic_vector(63 downto 0);
br_taken : std_ulogic; br_taken : std_ulogic;
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;
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); log_addr_spr : std_ulogic_vector(31 downto 0);
end record; end record;
constant reg_type_init : reg_type := constant reg_type_init : reg_type :=
@ -84,9 +74,6 @@ architecture behaviour of execute1 is
busy => '0', terminate => '0', busy => '0', terminate => '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, br_taken => '0',
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',
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')); others => (others => '0'));


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


signal valid_in : std_ulogic; signal valid_in : std_ulogic;
signal ctrl: ctrl_t := (irq_state => WRITE_SRR0, others => (others => '0')); signal ctrl: ctrl_t := (others => (others => '0'));
signal ctrl_tmp: ctrl_t := (irq_state => WRITE_SRR0, others => (others => '0')); signal ctrl_tmp: ctrl_t := (others => (others => '0'));
signal right_shift, rot_clear_left, rot_clear_right: std_ulogic; signal right_shift, rot_clear_left, rot_clear_right: std_ulogic;
signal rot_sign_ext: std_ulogic; signal rot_sign_ext: std_ulogic;
signal rotator_result: std_ulogic_vector(63 downto 0); 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; 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; 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; terminate_out <= r.terminate;


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


v := r; v := r;
v.e := Execute1ToWritebackInit; v.e := Execute1ToWritebackInit;
v.redirect := '0'; v.e.redir_mode := ctrl.msr(MSR_IR) & not ctrl.msr(MSR_PR) &
v.abs_br := '0'; not ctrl.msr(MSR_LE) & not ctrl.msr(MSR_SF);
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.xerc := xerc_in; v.e.xerc := xerc_in;


lv := Execute1ToLoadstore1Init; lv := Execute1ToLoadstore1Init;
@ -725,11 +702,11 @@ begin
irq_valid := '0'; irq_valid := '0';
if ctrl.msr(MSR_EE) = '1' then if ctrl.msr(MSR_EE) = '1' then
if ctrl.dec(63) = '1' then if ctrl.dec(63) = '1' then
v.vector := 16#900#; v.e.intr_vec := 16#900#;
report "IRQ valid: DEC"; report "IRQ valid: DEC";
irq_valid := '1'; irq_valid := '1';
elsif ext_irq_in = '1' then elsif ext_irq_in = '1' then
v.vector := 16#500#; v.e.intr_vec := 16#500#;
report "IRQ valid: External"; report "IRQ valid: External";
irq_valid := '1'; irq_valid := '1';
end if; 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_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'; rot_sign_ext <= '1' when e_in.insn_type = OP_EXTSWSLI else '0';


ctrl_tmp.srr1 <= msr_copy(ctrl.msr); v.e.srr1 := msr_copy(ctrl.msr);
ctrl_tmp.irq_state <= WRITE_SRR0;
exception := '0'; exception := '0';
illegal := '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 if valid_in = '1' then
v.e.exc_write_data := e_in.nia; v.e.last_nia := e_in.nia;
v.last_nia := e_in.nia;
else else
v.e.exc_write_data := r.last_nia; v.e.last_nia := r.e.last_nia;
end if; end if;


v.e.mode_32bit := not ctrl.msr(MSR_SF); v.e.mode_32bit := not ctrl.msr(MSR_SF);
@ -777,20 +749,20 @@ begin
-- 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'; exception := '1';
v.vector := 16#700#; v.e.intr_vec := 16#700#;
ctrl_tmp.srr1(63 - 43) <= '1'; v.e.srr1(63 - 43) := '1';
ctrl_tmp.srr1(63 - 47) <= '1'; v.e.srr1(63 - 47) := '1';
elsif r.trace_next = '1' then 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'; exception := '1';
v.vector := 16#d00#; v.e.intr_vec := 16#d00#;
ctrl_tmp.srr1(63 - 33) <= '1'; 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 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 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 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; end if;


elsif irq_valid = '1' then 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 elsif ctrl.msr(MSR_PR) = '1' and instr_is_privileged(e_in.insn_type, e_in.insn) then
-- generate a program interrupt -- generate a program interrupt
exception := '1'; exception := '1';
v.vector := 16#700#; v.e.intr_vec := 16#700#;
-- set bit 45 to indicate privileged instruction type interrupt -- set bit 45 to indicate privileged instruction type interrupt
ctrl_tmp.srr1(63 - 45) <= '1'; v.e.srr1(63 - 45) := '1';
report "privileged instruction"; report "privileged instruction";


elsif not HAS_FPU and e_in.fac = FPU then 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 elsif HAS_FPU and ctrl.msr(MSR_FP) = '0' and e_in.fac = FPU then
-- generate a floating-point unavailable interrupt -- generate a floating-point unavailable interrupt
exception := '1'; exception := '1';
v.vector := 16#800#; v.e.intr_vec := 16#800#;
report "FP unavailable interrupt"; report "FP unavailable interrupt";
end if; end if;
end if; end if;


if valid_in = '1' and exception = '0' and illegal = '0' and e_in.unit = ALU then if valid_in = '1' and exception = '0' and illegal = '0' and e_in.unit = ALU then
v.cur_instr := e_in; v.cur_instr := e_in;
v.next_lr := next_nia;
v.e.valid := '1'; v.e.valid := '1';


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


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


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


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


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


if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then
exception := '1'; exception := '1';
v.vector := 16#700#; v.e.intr_vec := 16#700#;
-- Since we aren't doing Hypervisor emulation assist (0xe40) we -- Since we aren't doing Hypervisor emulation assist (0xe40) we
-- set bit 44 to indicate we have an illegal -- set bit 44 to indicate we have an illegal
ctrl_tmp.srr1(63 - 44) <= '1'; v.e.srr1(63 - 44) := '1';
report "illegal"; report "illegal";
end if; 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 -- 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
if l_in.alignment = '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 elsif l_in.instr_fault = '0' then
if l_in.segment_fault = '0' then if l_in.segment_fault = '0' then
v.vector := 16#300#; v.e.intr_vec := 16#300#;
else else
v.vector := 16#380#; v.e.intr_vec := 16#380#;
end if; end if;
else else
if l_in.segment_fault = '0' then if l_in.segment_fault = '0' then
ctrl_tmp.srr1(63 - 33) <= l_in.invalid; v.e.srr1(63 - 33) := l_in.invalid;
ctrl_tmp.srr1(63 - 35) <= l_in.perm_error; -- noexec fault v.e.srr1(63 - 35) := l_in.perm_error; -- noexec fault
ctrl_tmp.srr1(63 - 44) <= l_in.badtree; v.e.srr1(63 - 44) := l_in.badtree;
ctrl_tmp.srr1(63 - 45) <= l_in.rc_error; v.e.srr1(63 - 45) := l_in.rc_error;
v.vector := 16#400#; v.e.intr_vec := 16#400#;
else else
v.vector := 16#480#; v.e.intr_vec := 16#480#;
end if; end if;
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; end if;


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


if do_trace = '1' then if do_trace = '1' then
v.trace_next := '1'; v.trace_next := '1';
end if; 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 if hold_wr_data = '0' then
v.e.write_data := alu_result; v.e.write_data := alu_result;
else else
@ -1263,41 +1217,6 @@ begin
end if; end if;
end loop; 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) -- Outputs to loadstore1 (async)
lv.op := e_in.insn_type; lv.op := e_in.insn_type;
lv.nia := e_in.nia; lv.nia := e_in.nia;
@ -1344,11 +1263,9 @@ begin
rin <= v; rin <= v;


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


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

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


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


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


btc_ram : process(clk) btc_ram : process(clk)
variable raddr : unsigned(BTC_ADDR_BITS - 1 downto 0); variable raddr : unsigned(BTC_ADDR_BITS - 1 downto 0);
@ -158,15 +158,15 @@ begin
v.big_endian := '0'; v.big_endian := '0';
v_int.mode_32bit := '0'; v_int.mode_32bit := '0';
v_int.predicted_nia := (others => '0'); v_int.predicted_nia := (others => '0');
elsif e_in.redirect = '1' then elsif w_in.redirect = '1' then
v.nia := e_in.redirect_nia(63 downto 2) & "00"; v.nia := w_in.redirect_nia(63 downto 2) & "00";
if e_in.mode_32bit = '1' then if w_in.mode_32bit = '1' then
v.nia(63 downto 32) := (others => '0'); v.nia(63 downto 32) := (others => '0');
end if; end if;
v.virt_mode := e_in.virt_mode; v.virt_mode := w_in.virt_mode;
v.priv_mode := e_in.priv_mode; v.priv_mode := w_in.priv_mode;
v.big_endian := e_in.big_endian; v.big_endian := w_in.big_endian;
v_int.mode_32bit := e_in.mode_32bit; v_int.mode_32bit := w_in.mode_32bit;
elsif d_in.redirect = '1' then elsif d_in.redirect = '1' then
v.nia := d_in.redirect_nia(63 downto 2) & "00"; v.nia := d_in.redirect_nia(63 downto 2) & "00";
if r_int.mode_32bit = '1' then 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 -- If the last NIA value went down with a stop mark, it didn't get
-- executed, and hence we shouldn't increment NIA. -- 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 <= v;
r_next_int <= v_int; r_next_int <= v_int;

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


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


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


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


architecture behaviour of writeback is 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 begin
writeback_0: process(clk) writeback_0: process(clk)
variable x : std_ulogic_vector(0 downto 0); variable x : std_ulogic_vector(0 downto 0);
@ -29,6 +42,13 @@ begin
variable w : std_ulogic_vector(0 downto 0); variable w : std_ulogic_vector(0 downto 0);
begin begin
if rising_edge(clk) then 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 -- Do consistency checks only on the clock edge
x(0) := e_in.valid; x(0) := e_in.valid;
y(0) := l_in.valid; y(0) := l_in.valid;
@ -36,7 +56,7 @@ begin
assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) + assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
to_integer(unsigned(w))) <= 1 severity failure; 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; y(0) := l_in.write_enable;
w(0) := fp_in.write_enable; w(0) := fp_in.write_enable;
assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) + assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
@ -55,6 +75,8 @@ begin
end process; end process;


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


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


if e_in.exc_write_enable = '1' then if r.state = WRITE_SRR1 then
w_out.write_reg <= e_in.exc_write_reg; w_out.write_reg <= fast_spr_num(SPR_SRR1);
w_out.write_data <= e_in.exc_write_data; 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'; w_out.write_enable <= '1';
v.state := WRITE_SRR1;
v.srr1 := e_in.srr1;
else else
if e_in.write_enable = '1' then if e_in.write_enable = '1' then
w_out.write_reg <= e_in.write_reg; w_out.write_reg <= e_in.write_reg;
@ -142,5 +176,35 @@ begin
c_out.write_cr_data(31 downto 28) <= cf; c_out.write_cr_data(31 downto 28) <= cf;
end if; end if;
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 process;
end; end;

Loading…
Cancel
Save