Merge pull request #65 from antonblanchard/loadstore-opt

A small loadstore optimisation, and some reformatting
pull/67/head
Anton Blanchard 5 years ago committed by GitHub
commit c5d327cebf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,55 +10,55 @@ use work.helpers.all;
-- We calculate the address in the first cycle -- We calculate the address in the first cycle


entity loadstore1 is entity loadstore1 is
port ( port (
clk : in std_ulogic; clk : in std_ulogic;


l_in : in Decode2ToLoadstore1Type; l_in : in Decode2ToLoadstore1Type;


l_out : out Loadstore1ToLoadstore2Type l_out : out Loadstore1ToLoadstore2Type
); );
end loadstore1; end loadstore1;


architecture behave of loadstore1 is architecture behave of loadstore1 is
signal r, rin : Loadstore1ToLoadstore2Type; signal r, rin : Loadstore1ToLoadstore2Type;
signal lsu_sum : std_ulogic_vector(63 downto 0); signal lsu_sum : std_ulogic_vector(63 downto 0);
begin begin
-- Calculate the address in the first cycle -- Calculate the address in the first cycle
lsu_sum <= std_ulogic_vector(unsigned(l_in.addr1) + unsigned(l_in.addr2)) when l_in.valid = '1' else (others => '0'); lsu_sum <= std_ulogic_vector(unsigned(l_in.addr1) + unsigned(l_in.addr2)) when l_in.valid = '1' else (others => '0');


loadstore1_0: process(clk) loadstore1_0: process(clk)
begin begin
if rising_edge(clk) then if rising_edge(clk) then
r <= rin; r <= rin;
end if; end if;
end process; end process;


loadstore1_1: process(all) loadstore1_1: process(all)
variable v : Loadstore1ToLoadstore2Type; variable v : Loadstore1ToLoadstore2Type;
begin begin
v := r; v := r;


v.valid := l_in.valid; v.valid := l_in.valid;
v.load := l_in.load; v.load := l_in.load;
v.data := l_in.data; v.data := l_in.data;
v.write_reg := l_in.write_reg; v.write_reg := l_in.write_reg;
v.length := l_in.length; v.length := l_in.length;
v.byte_reverse := l_in.byte_reverse; v.byte_reverse := l_in.byte_reverse;
v.sign_extend := l_in.sign_extend; v.sign_extend := l_in.sign_extend;
v.update := l_in.update; v.update := l_in.update;
v.update_reg := l_in.update_reg; v.update_reg := l_in.update_reg;


-- byte reverse stores in the first cycle -- byte reverse stores in the first cycle
if v.load = '0' and l_in.byte_reverse = '1' then if v.load = '0' and l_in.byte_reverse = '1' then
v.data := byte_reverse(l_in.data, to_integer(unsigned(l_in.length))); v.data := byte_reverse(l_in.data, to_integer(unsigned(l_in.length)));
end if; end if;


v.addr := lsu_sum; v.addr := lsu_sum;


-- Update registers -- Update registers
rin <= v; rin <= v;


-- Update outputs -- Update outputs
l_out <= r; l_out <= r;
end process; end process;
end; end;

@ -11,154 +11,157 @@ use work.wishbone_types.all;
-- In this cycle we read or write any data and do sign extension and update if required. -- In this cycle we read or write any data and do sign extension and update if required.


entity loadstore2 is entity loadstore2 is
port ( port (
clk : in std_ulogic; clk : in std_ulogic;


l_in : in Loadstore1ToLoadstore2Type; l_in : in Loadstore1ToLoadstore2Type;
w_out : out Loadstore2ToWritebackType; w_out : out Loadstore2ToWritebackType;


m_in : in wishbone_slave_out; m_in : in wishbone_slave_out;
m_out : out wishbone_master_out m_out : out wishbone_master_out
); );
end loadstore2; end loadstore2;


architecture behave of loadstore2 is architecture behave of loadstore2 is
signal l_saved : Loadstore1ToLoadstore2Type; signal l_saved : Loadstore1ToLoadstore2Type;
signal w_tmp : Loadstore2ToWritebackType; signal w_tmp : Loadstore2ToWritebackType;
signal m_tmp : wishbone_master_out; signal m_tmp : wishbone_master_out;


type state_t is (IDLE, WAITING_FOR_READ_ACK, WAITING_FOR_WRITE_ACK); type state_t is (IDLE, WAITING_FOR_READ_ACK, WAITING_FOR_WRITE_ACK);
signal state : state_t := IDLE; signal state : state_t := IDLE;


function length_to_sel(length : in std_logic_vector(3 downto 0)) return std_ulogic_vector is function length_to_sel(length : in std_logic_vector(3 downto 0)) return std_ulogic_vector is
begin begin
case length is case length is
when "0001" => when "0001" =>
return "00000001"; return "00000001";
when "0010" => when "0010" =>
return "00000011"; return "00000011";
when "0100" => when "0100" =>
return "00001111"; return "00001111";
when "1000" => when "1000" =>
return "11111111"; return "11111111";
when others => when others =>
return "00000000"; return "00000000";
end case; end case;
end function length_to_sel; end function length_to_sel;


function wishbone_data_shift(address : in std_ulogic_vector(63 downto 0)) return natural is function wishbone_data_shift(address : in std_ulogic_vector(63 downto 0)) return natural is
begin begin
return to_integer(unsigned(address(2 downto 0))) * 8; return to_integer(unsigned(address(2 downto 0))) * 8;
end function wishbone_data_shift; end function wishbone_data_shift;


function wishbone_data_sel(size : in std_logic_vector(3 downto 0); address : in std_logic_vector(63 downto 0)) return std_ulogic_vector is function wishbone_data_sel(size : in std_logic_vector(3 downto 0); address : in std_logic_vector(63 downto 0)) return std_ulogic_vector is
begin begin
return std_ulogic_vector(shift_left(unsigned(length_to_sel(size)), to_integer(unsigned(address(2 downto 0))))); return std_ulogic_vector(shift_left(unsigned(length_to_sel(size)), to_integer(unsigned(address(2 downto 0)))));
end function wishbone_data_sel; end function wishbone_data_sel;
begin begin
w_out <= w_tmp; w_out <= w_tmp;
m_out <= m_tmp; m_out <= m_tmp;


loadstore2_0: process(clk) loadstore2_0: process(clk)
variable tmp : std_ulogic_vector(63 downto 0); variable tmp : std_ulogic_vector(63 downto 0);
variable data : std_ulogic_vector(63 downto 0); variable data : std_ulogic_vector(63 downto 0);
begin variable sign_extend_byte_reverse : std_ulogic_vector(1 downto 0);
if rising_edge(clk) then begin
tmp := (others => '0'); if rising_edge(clk) then
data := (others => '0'); tmp := (others => '0');

data := (others => '0');
w_tmp <= Loadstore2ToWritebackInit;

w_tmp <= Loadstore2ToWritebackInit;
l_saved <= l_saved;

l_saved <= l_saved;
case_0: case state is
when IDLE => case_0: case state is
if l_in.valid = '1' then when IDLE =>
m_tmp <= wishbone_master_out_init; if l_in.valid = '1' then

m_tmp <= wishbone_master_out_init;
m_tmp.sel <= wishbone_data_sel(l_in.length, l_in.addr);
m_tmp.adr <= l_in.addr(63 downto 3) & "000"; m_tmp.sel <= wishbone_data_sel(l_in.length, l_in.addr);
m_tmp.cyc <= '1'; m_tmp.adr <= l_in.addr(63 downto 3) & "000";
m_tmp.stb <= '1'; m_tmp.cyc <= '1';

m_tmp.stb <= '1';
l_saved <= l_in;

l_saved <= l_in;
if l_in.load = '1' then
m_tmp.we <= '0'; if l_in.load = '1' then

m_tmp.we <= '0';
-- Load with update instructions write two GPR destinations.
-- We don't want the expense of two write ports, so make it -- Load with update instructions write two GPR destinations.
-- single in the pipeline and write back the update GPR now -- We don't want the expense of two write ports, so make it
-- and the load once we get the data back. We'll have to -- single in the pipeline and write back the update GPR now
-- revisit this when loads can take exceptions. -- and the load once we get the data back. We'll have to
if l_in.update = '1' then -- revisit this when loads can take exceptions.
w_tmp.write_enable <= '1'; if l_in.update = '1' then
w_tmp.write_reg <= l_in.update_reg; w_tmp.write_enable <= '1';
w_tmp.write_data <= l_in.addr; w_tmp.write_reg <= l_in.update_reg;
end if; w_tmp.write_data <= l_in.addr;

end if;
state <= WAITING_FOR_READ_ACK;
else state <= WAITING_FOR_READ_ACK;
m_tmp.we <= '1'; else

m_tmp.we <= '1';
data := l_in.data;
m_tmp.dat <= std_logic_vector(shift_left(unsigned(data), wishbone_data_shift(l_in.addr))); data := l_in.data;

m_tmp.dat <= std_logic_vector(shift_left(unsigned(data), wishbone_data_shift(l_in.addr)));
assert l_in.sign_extend = '0' report "sign extension doesn't make sense for stores" severity failure;

assert l_in.sign_extend = '0' report "sign extension doesn't make sense for stores" severity failure;
state <= WAITING_FOR_WRITE_ACK;
end if; state <= WAITING_FOR_WRITE_ACK;
end if; end if;

end if;
when WAITING_FOR_READ_ACK =>
if m_in.ack = '1' then when WAITING_FOR_READ_ACK =>
tmp := std_logic_vector(shift_right(unsigned(m_in.dat), wishbone_data_shift(l_saved.addr))); if m_in.ack = '1' then
case to_integer(unsigned(l_saved.length)) is tmp := std_logic_vector(shift_right(unsigned(m_in.dat), wishbone_data_shift(l_saved.addr)));
when 0 => case to_integer(unsigned(l_saved.length)) is
when 1 => when 0 =>
data(7 downto 0) := tmp(7 downto 0); when 1 =>
when 2 => data(7 downto 0) := tmp(7 downto 0);
data(15 downto 0) := tmp(15 downto 0); when 2 =>
when 4 => data(15 downto 0) := tmp(15 downto 0);
data(31 downto 0) := tmp(31 downto 0); when 4 =>
when 8 => data(31 downto 0) := tmp(31 downto 0);
data(63 downto 0) := tmp(63 downto 0); when 8 =>
when others => data(63 downto 0) := tmp(63 downto 0);
assert false report "invalid length" severity failure; when others =>
end case; assert false report "invalid length" severity failure;

end case;
if l_saved.sign_extend = '1' then
data := sign_extend(data, to_integer(unsigned(l_saved.length))); sign_extend_byte_reverse := l_saved.sign_extend & l_saved.byte_reverse;
end if;

case sign_extend_byte_reverse is
if l_saved.byte_reverse = '1' then when "10" =>
data := byte_reverse(data, to_integer(unsigned(l_saved.length))); data := sign_extend(data, to_integer(unsigned(l_saved.length)));
end if; when "01" =>

data := byte_reverse(data, to_integer(unsigned(l_saved.length)));
w_tmp.write_data <= data; when others =>

end case;
-- write data to register file
w_tmp.valid <= '1'; w_tmp.write_data <= data;
w_tmp.write_enable <= '1';
w_tmp.write_reg <= l_saved.write_reg; -- write data to register file

w_tmp.valid <= '1';
m_tmp <= wishbone_master_out_init; w_tmp.write_enable <= '1';
state <= IDLE; w_tmp.write_reg <= l_saved.write_reg;
end if;

m_tmp <= wishbone_master_out_init;
when WAITING_FOR_WRITE_ACK => state <= IDLE;
if m_in.ack = '1' then end if;
w_tmp.valid <= '1';
if l_saved.update = '1' then when WAITING_FOR_WRITE_ACK =>
w_tmp.write_enable <= '1'; if m_in.ack = '1' then
w_tmp.write_reg <= l_saved.update_reg; w_tmp.valid <= '1';
w_tmp.write_data <= l_saved.addr; if l_saved.update = '1' then
end if; w_tmp.write_enable <= '1';

w_tmp.write_reg <= l_saved.update_reg;
m_tmp <= wishbone_master_out_init; w_tmp.write_data <= l_saved.addr;
state <= IDLE; end if;
end if;
end case; m_tmp <= wishbone_master_out_init;
end if; state <= IDLE;
end process; end if;
end case;
end if;
end process;
end; end;

Loading…
Cancel
Save