1
0
mirror of https://github.com/antonblanchard/microwatt.git synced 2026-01-13 15:18:09 +00:00
Anton Blanchard 9fbaea6f08 Rework CR file and add forwarding
Handle the CR as a single field with per nibble enables. Forward any
writes in the same cycle.

If this proves to be an issue for timing, we may want to revisit
this in the future. For now, it keeps things simple.

Signed-off-by: Anton Blanchard <anton@linux.ibm.com>
2019-09-09 10:18:10 +10:00

302 lines
8.4 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.decode_types.all;
use work.common.all;
use work.helpers.all;
use work.insn_helpers.all;
entity decode2 is
port (
clk : in std_ulogic;
d_in : in Decode1ToDecode2Type;
e_out : out Decode2ToExecute1Type;
m_out : out Decode2ToMultiplyType;
l_out : out Decode2ToLoadstore1Type;
r_in : in RegisterFileToDecode2Type;
r_out : out Decode2ToRegisterFileType;
c_in : in CrFileToDecode2Type;
c_out : out Decode2ToCrFileType
);
end entity decode2;
architecture behaviour of decode2 is
signal d : Decode1ToDecode2Type;
type decode_input_reg_t is record
reg_valid : std_ulogic;
reg : std_ulogic_vector(4 downto 0);
data : std_ulogic_vector(63 downto 0);
end record;
function decode_input_reg_a (t : input_reg_a_t; insn_in : std_ulogic_vector(31 downto 0);
reg_data : std_ulogic_vector(63 downto 0)) return decode_input_reg_t is
begin
case t is
when RA =>
return ('1', insn_ra(insn_in), reg_data);
when RA_OR_ZERO =>
return ('1', insn_ra(insn_in), ra_or_zero(reg_data, insn_ra(insn_in)));
when RS =>
return ('1', insn_rs(insn_in), reg_data);
when NONE =>
return ('0', (others => '0'), (others => '0'));
end case;
end;
function decode_input_reg_b (t : input_reg_b_t; insn_in : std_ulogic_vector(31 downto 0);
reg_data : std_ulogic_vector(63 downto 0)) return decode_input_reg_t is
begin
case t is
when RB =>
return ('1', insn_rb(insn_in), reg_data);
when RS =>
return ('1', insn_rs(insn_in), reg_data);
when CONST_UI =>
return ('0', (others => '0'), std_ulogic_vector(resize(unsigned(insn_ui(insn_in)), 64)));
when CONST_SI =>
return ('0', (others => '0'), std_ulogic_vector(resize(signed(insn_si(insn_in)), 64)));
when CONST_SI_HI =>
return ('0', (others => '0'), std_ulogic_vector(resize(signed(insn_si(insn_in)) & x"0000", 64)));
when CONST_UI_HI =>
return ('0', (others => '0'), std_ulogic_vector(resize(unsigned(insn_si(insn_in)) & x"0000", 64)));
when CONST_LI =>
return ('0', (others => '0'), std_ulogic_vector(resize(signed(insn_li(insn_in)) & "00", 64)));
when CONST_BD =>
return ('0', (others => '0'), std_ulogic_vector(resize(signed(insn_bd(insn_in)) & "00", 64)));
when CONST_DS =>
return ('0', (others => '0'), std_ulogic_vector(resize(signed(insn_ds(insn_in)) & "00", 64)));
when NONE =>
return ('0', (others => '0'), (others => '0'));
end case;
end;
function decode_input_reg_c (t : input_reg_c_t; insn_in : std_ulogic_vector(31 downto 0);
reg_data : std_ulogic_vector(63 downto 0)) return decode_input_reg_t is
begin
case t is
when RS =>
return ('1', insn_rs(insn_in), reg_data);
when NONE =>
return ('0', (others => '0'), (others => '0'));
end case;
end;
function decode_output_reg (t : output_reg_a_t; insn_in : std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
begin
case t is
when RT =>
return insn_rt(insn_in);
when RA =>
return insn_ra(insn_in);
when NONE =>
return "00000";
end case;
end;
function decode_const_a (t : constant_a_t; insn_in : std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
begin
case t is
when SH =>
return "00" & insn_sh(insn_in);
when SH32 =>
return "000" & insn_sh32(insn_in);
when FXM =>
return insn_fxm(insn_in);
when BO =>
return "000" & insn_bo(insn_in);
when BF =>
return "00000" & insn_bf(insn_in);
when TOO =>
return "000" & insn_to(insn_in);
when BC =>
return "000" & insn_bc(insn_in);
when NONE =>
return "00000000";
end case;
end;
function decode_const_b (t : constant_b_t; insn_in : std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
begin
case t is
when MB =>
return insn_mb(insn_in);
when ME =>
return insn_me(insn_in);
when MB32 =>
return "0" & insn_mb32(insn_in);
when BI =>
return "0" & insn_bi(insn_in);
when L =>
return "00000" & insn_l(insn_in);
when NONE =>
return "000000";
end case;
end;
function decode_const_c (t : constant_c_t; insn_in : std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
begin
case t is
when ME32 =>
return insn_me32(insn_in);
when BH =>
return "000" & insn_bh(insn_in);
when NONE =>
return "00000";
end case;
end;
function decode_rc (t : rc_t; insn_in : std_ulogic_vector(31 downto 0)) return std_ulogic is
begin
case t is
when RC =>
return insn_rc(insn_in);
when ONE =>
return '1';
when NONE =>
return '0';
end case;
end;
begin
decode2_0: process(clk)
begin
if rising_edge(clk) then
d <= d_in;
end if;
end process;
r_out.read1_reg <= insn_ra(d.insn) when (d.decode.input_reg_a = RA) else
insn_ra(d.insn) when d.decode.input_reg_a = RA_OR_ZERO else
insn_rs(d.insn) when d.decode.input_reg_a = RS else
(others => '0');
r_out.read2_reg <= insn_rb(d.insn) when d.decode.input_reg_b = RB else
insn_rs(d.insn) when d.decode.input_reg_b = RS else
(others => '0');
r_out.read3_reg <= insn_rs(d.insn) when d.decode.input_reg_c = RS else
(others => '0');
c_out.read <= d.decode.input_cr;
decode2_1: process(all)
variable mul_a : std_ulogic_vector(63 downto 0);
variable mul_b : std_ulogic_vector(63 downto 0);
variable decoded_reg_a : decode_input_reg_t;
variable decoded_reg_b : decode_input_reg_t;
variable decoded_reg_c : decode_input_reg_t;
begin
e_out <= Decode2ToExecute1Init;
l_out <= Decode2ToLoadStore1Init;
m_out <= Decode2ToMultiplyInit;
mul_a := (others => '0');
mul_b := (others => '0');
--e_out.input_cr <= d.decode.input_cr;
--m_out.input_cr <= d.decode.input_cr;
--e_out.output_cr <= d.decode.output_cr;
decoded_reg_a := decode_input_reg_a (d.decode.input_reg_a, d.insn, r_in.read1_data);
decoded_reg_b := decode_input_reg_b (d.decode.input_reg_b, d.insn, r_in.read2_data);
decoded_reg_c := decode_input_reg_c (d.decode.input_reg_c, d.insn, r_in.read3_data);
case d.decode.unit is
when ALU =>
e_out.valid <= d.valid;
when LDST =>
l_out.valid <= d.valid;
when MUL =>
m_out.valid <= d.valid;
when NONE =>
e_out.valid <= d.valid;
e_out.insn_type <= OP_ILLEGAL;
end case;
-- execute unit
e_out.nia <= d.nia;
e_out.insn_type <= d.decode.insn_type;
e_out.read_reg1 <= decoded_reg_a.reg;
e_out.read_data1 <= decoded_reg_a.data;
e_out.read_reg2 <= decoded_reg_b.reg;
e_out.read_data2 <= decoded_reg_b.data;
e_out.write_reg <= decode_output_reg(d.decode.output_reg_a, d.insn);
e_out.rc <= decode_rc(d.decode.rc, d.insn);
e_out.cr <= c_in.read_cr_data;
e_out.input_carry <= d.decode.input_carry;
e_out.output_carry <= d.decode.output_carry;
if d.decode.lr then
e_out.lr <= insn_lk(d.insn);
end if;
e_out.const1 <= decode_const_a(d.decode.const_a, d.insn);
e_out.const2 <= decode_const_b(d.decode.const_b, d.insn);
e_out.const3 <= decode_const_c(d.decode.const_c, d.insn);
-- multiply unit
m_out.nia <= d.nia;
m_out.insn_type <= d.decode.insn_type;
mul_a := decoded_reg_a.data;
mul_b := decoded_reg_b.data;
m_out.write_reg <= decode_output_reg(d.decode.output_reg_a, d.insn);
m_out.rc <= decode_rc(d.decode.rc, d.insn);
if d.decode.mul_32bit = '1' then
if d.decode.mul_signed = '1' then
m_out.data1 <= (others => mul_a(31));
m_out.data1(31 downto 0) <= mul_a(31 downto 0);
m_out.data2 <= (others => mul_b(31));
m_out.data2(31 downto 0) <= mul_b(31 downto 0);
else
m_out.data1 <= '0' & x"00000000" & mul_a(31 downto 0);
m_out.data2 <= '0' & x"00000000" & mul_b(31 downto 0);
end if;
else
if d.decode.mul_signed = '1' then
m_out.data1 <= mul_a(63) & mul_a;
m_out.data2 <= mul_b(63) & mul_b;
else
m_out.data1 <= '0' & mul_a;
m_out.data2 <= '0' & mul_b;
end if;
end if;
-- load/store unit
l_out.nia <= d.nia;
l_out.update_reg <= decoded_reg_a.reg;
l_out.addr1 <= decoded_reg_a.data;
l_out.addr2 <= decoded_reg_b.data;
l_out.data <= decoded_reg_c.data;
l_out.write_reg <= decode_output_reg(d.decode.output_reg_a, d.insn);
if d.decode.insn_type = OP_LOAD then
l_out.load <= '1';
else
l_out.load <= '0';
end if;
case d.decode.length is
when is1B =>
l_out.length <= "0001";
when is2B =>
l_out.length <= "0010";
when is4B =>
l_out.length <= "0100";
when is8B =>
l_out.length <= "1000";
when NONE =>
l_out.length <= "0000";
end case;
l_out.byte_reverse <= d.decode.byte_reverse;
l_out.sign_extend <= d.decode.sign_extend;
l_out.update <= d.decode.update;
end process;
end architecture behaviour;