mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
In order to improve timing, the bypass paths now carry the register number being written as well as the tag. The decisions about which bypasses to use for which operands are then made by comparing the register numbers rather than by determining a tag from the register number and then comparing tags. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
211 lines
7.1 KiB
VHDL
211 lines
7.1 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.common.all;
|
|
use work.crhelpers.all;
|
|
|
|
entity writeback is
|
|
port (
|
|
clk : in std_ulogic;
|
|
rst : in std_ulogic;
|
|
|
|
e_in : in Execute1ToWritebackType;
|
|
l_in : in Loadstore1ToWritebackType;
|
|
fp_in : in FPUToWritebackType;
|
|
|
|
w_out : out WritebackToRegisterFileType;
|
|
c_out : out WritebackToCrFileType;
|
|
f_out : out WritebackToFetch1Type;
|
|
|
|
wb_bypass : out bypass_data_t;
|
|
|
|
-- PMU event bus
|
|
events : out WritebackEventType;
|
|
|
|
flush_out : out std_ulogic;
|
|
interrupt_out: out WritebackToExecute1Type;
|
|
complete_out : out instr_tag_t
|
|
);
|
|
end entity writeback;
|
|
|
|
architecture behaviour of writeback is
|
|
|
|
begin
|
|
writeback_0: process(clk)
|
|
variable x : std_ulogic_vector(0 downto 0);
|
|
variable y : std_ulogic_vector(0 downto 0);
|
|
variable w : std_ulogic_vector(0 downto 0);
|
|
begin
|
|
if rising_edge(clk) then
|
|
-- Do consistency checks only on the clock edge
|
|
x(0) := e_in.valid;
|
|
y(0) := l_in.valid;
|
|
w(0) := fp_in.valid;
|
|
assert (to_integer(unsigned(x)) + to_integer(unsigned(y)) +
|
|
to_integer(unsigned(w))) <= 1 severity failure;
|
|
|
|
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)) +
|
|
to_integer(unsigned(w))) <= 1 severity failure;
|
|
|
|
w(0) := e_in.write_cr_enable;
|
|
x(0) := l_in.rc;
|
|
y(0) := fp_in.write_cr_enable;
|
|
assert (to_integer(unsigned(w)) + to_integer(unsigned(x)) +
|
|
to_integer(unsigned(y))) <= 1 severity failure;
|
|
|
|
assert (e_in.write_xerc_enable and fp_in.write_xerc) /= '1' severity failure;
|
|
|
|
assert not (e_in.valid = '1' and e_in.instr_tag.valid = '0') severity failure;
|
|
assert not (l_in.valid = '1' and l_in.instr_tag.valid = '0') severity failure;
|
|
assert not (fp_in.valid = '1' and fp_in.instr_tag.valid = '0') severity failure;
|
|
end if;
|
|
end process;
|
|
|
|
writeback_1: process(all)
|
|
variable f : WritebackToFetch1Type;
|
|
variable scf : std_ulogic_vector(3 downto 0);
|
|
variable vec : integer range 0 to 16#fff#;
|
|
variable srr1 : std_ulogic_vector(15 downto 0);
|
|
variable intr : std_ulogic;
|
|
variable hvi : std_ulogic;
|
|
variable scv : std_ulogic;
|
|
variable intr_page : std_ulogic_vector(4 downto 0);
|
|
variable intr_seg : std_ulogic_vector(1 downto 0);
|
|
begin
|
|
w_out <= WritebackToRegisterFileInit;
|
|
c_out <= WritebackToCrFileInit;
|
|
f := WritebackToFetch1Init;
|
|
vec := 0;
|
|
hvi := '0';
|
|
|
|
complete_out <= instr_tag_init;
|
|
if e_in.valid = '1' then
|
|
complete_out <= e_in.instr_tag;
|
|
elsif l_in.valid = '1' then
|
|
complete_out <= l_in.instr_tag;
|
|
elsif fp_in.valid = '1' then
|
|
complete_out <= fp_in.instr_tag;
|
|
end if;
|
|
events.instr_complete <= complete_out.valid;
|
|
events.fp_complete <= fp_in.valid;
|
|
|
|
intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt;
|
|
interrupt_out.intr <= intr;
|
|
|
|
srr1 := (others => '0');
|
|
intr_page := 5x"0";
|
|
if e_in.alt_intr = '1' then
|
|
intr_page := 5x"4";
|
|
end if;
|
|
intr_seg := e_in.alt_intr & e_in.alt_intr;
|
|
scv := '0';
|
|
if e_in.interrupt = '1' then
|
|
vec := e_in.intr_vec;
|
|
srr1 := e_in.srr1;
|
|
hvi := e_in.hv_intr;
|
|
scv := e_in.is_scv;
|
|
if e_in.is_scv = '1' then
|
|
if e_in.alt_intr = '0' then
|
|
intr_page := 5x"17";
|
|
else
|
|
intr_page := 5x"3";
|
|
end if;
|
|
end if;
|
|
elsif l_in.interrupt = '1' then
|
|
vec := l_in.intr_vec;
|
|
srr1 := l_in.srr1;
|
|
elsif fp_in.interrupt = '1' then
|
|
vec := fp_in.intr_vec;
|
|
srr1 := fp_in.srr1;
|
|
end if;
|
|
interrupt_out.hv_intr <= hvi;
|
|
interrupt_out.srr1 <= srr1;
|
|
interrupt_out.scv_int <= scv;
|
|
interrupt_out.alt_int <= e_in.alt_intr;
|
|
|
|
if intr = '0' then
|
|
if e_in.write_enable = '1' then
|
|
w_out.write_reg <= e_in.write_reg;
|
|
w_out.write_data <= e_in.write_data;
|
|
w_out.write_enable <= '1';
|
|
end if;
|
|
|
|
if e_in.write_cr_enable = '1' then
|
|
c_out.write_cr_enable <= '1';
|
|
c_out.write_cr_mask <= e_in.write_cr_mask;
|
|
c_out.write_cr_data <= e_in.write_cr_data;
|
|
end if;
|
|
|
|
if e_in.write_xerc_enable = '1' then
|
|
c_out.write_xerc_enable <= '1';
|
|
c_out.write_xerc_data <= e_in.xerc;
|
|
end if;
|
|
|
|
if fp_in.write_enable = '1' then
|
|
w_out.write_reg <= fp_in.write_reg;
|
|
w_out.write_data <= fp_in.write_data;
|
|
w_out.write_enable <= '1';
|
|
end if;
|
|
|
|
if fp_in.write_cr_enable = '1' then
|
|
c_out.write_cr_enable <= '1';
|
|
c_out.write_cr_mask <= fp_in.write_cr_mask;
|
|
c_out.write_cr_data <= fp_in.write_cr_data;
|
|
end if;
|
|
|
|
if fp_in.write_xerc = '1' then
|
|
c_out.write_xerc_enable <= '1';
|
|
c_out.write_xerc_data <= fp_in.xerc;
|
|
end if;
|
|
|
|
if l_in.write_enable = '1' then
|
|
w_out.write_reg <= l_in.write_reg;
|
|
w_out.write_data <= l_in.write_data;
|
|
w_out.write_enable <= '1';
|
|
end if;
|
|
|
|
if l_in.rc = '1' then
|
|
-- st*cx. instructions
|
|
scf(3) := '0';
|
|
scf(2) := '0';
|
|
scf(1) := l_in.store_done;
|
|
scf(0) := l_in.xerc.so;
|
|
c_out.write_cr_enable <= '1';
|
|
c_out.write_cr_mask <= num_to_fxm(0);
|
|
c_out.write_cr_data(31 downto 28) <= scf;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
-- Outputs to fetch1
|
|
f.interrupt := intr;
|
|
f.alt_intr := e_in.alt_intr;
|
|
f.intr_vec := intr_seg & 45x"0" & intr_page & std_ulogic_vector(to_unsigned(vec, 12));
|
|
f.redirect := e_in.redirect;
|
|
f.redirect_nia := e_in.write_data;
|
|
f.br_nia := e_in.last_nia;
|
|
f.br_last := e_in.br_last and not intr;
|
|
f.br_taken := e_in.br_taken;
|
|
-- 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);
|
|
|
|
f_out <= f;
|
|
flush_out <= f_out.redirect or intr;
|
|
|
|
-- Register write data bypass to decode2
|
|
wb_bypass.tag.tag <= complete_out.tag;
|
|
wb_bypass.tag.valid <= complete_out.valid and w_out.write_enable;
|
|
wb_bypass.reg <= w_out.write_reg;
|
|
wb_bypass.data <= w_out.write_data;
|
|
|
|
end process;
|
|
end;
|