mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
This starts the process of removing SPRs from the register file by moving SRR0/1, SPRG0-3, HSRR0/1 and HSPRG0/1 out of the register file and putting them into execute1. They are stored in a pair of small RAM arrays, referred to as "even" and "odd". The reason for having two arrays is so that two values can be read and written in each cycle. For example, SRR0 and SRR1 can be written in parallel by an interrupt and read in parallel by the rfid instruction. The addresses in the RAM which will be accessed are determined in the decode2 stage. We have one write address for both sides, but two read addresses, since in future we will want to be able to read CTR at the same time as either LR or TAR. We now have a connection from writeback to execute1 which carries the partial SRR1 value for an interrupt. SRR0 comes from the execute pipeline; we no longer need to carry instruction addresses along the LSU and FPU pipelines. Since SRR0 and SRR1 can be written in the same cycle now, we don't need the little state machine in writeback any more. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
200 lines
6.8 KiB
VHDL
200 lines
6.8 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;
|
|
begin
|
|
w_out <= WritebackToRegisterFileInit;
|
|
c_out <= WritebackToCrFileInit;
|
|
f := WritebackToFetch1Init;
|
|
vec := 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;
|
|
|
|
if intr = '1' then
|
|
srr1 := (others => '0');
|
|
if e_in.interrupt = '1' then
|
|
vec := e_in.intr_vec;
|
|
srr1 := e_in.srr1;
|
|
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.srr1 <= srr1;
|
|
|
|
else
|
|
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.redirect := e_in.redirect;
|
|
f.br_nia := e_in.last_nia;
|
|
f.br_last := e_in.br_last;
|
|
f.br_taken := e_in.br_taken;
|
|
if intr = '1' then
|
|
f.redirect := '1';
|
|
f.br_last := '0';
|
|
f.redirect_nia := std_ulogic_vector(to_unsigned(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;
|
|
|
|
-- 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.data <= w_out.write_data;
|
|
|
|
end process;
|
|
end;
|