mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-21 18:05:15 +00:00
Merge pull request #65 from antonblanchard/loadstore-opt
A small loadstore optimisation, and some reformatting
This commit is contained in:
commit
c5d327cebf
@ -10,55 +10,55 @@ use work.helpers.all;
|
||||
-- We calculate the address in the first cycle
|
||||
|
||||
entity loadstore1 is
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
|
||||
l_in : in Decode2ToLoadstore1Type;
|
||||
l_in : in Decode2ToLoadstore1Type;
|
||||
|
||||
l_out : out Loadstore1ToLoadstore2Type
|
||||
);
|
||||
l_out : out Loadstore1ToLoadstore2Type
|
||||
);
|
||||
end loadstore1;
|
||||
|
||||
architecture behave of loadstore1 is
|
||||
signal r, rin : Loadstore1ToLoadstore2Type;
|
||||
signal lsu_sum : std_ulogic_vector(63 downto 0);
|
||||
signal r, rin : Loadstore1ToLoadstore2Type;
|
||||
signal lsu_sum : std_ulogic_vector(63 downto 0);
|
||||
begin
|
||||
-- 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');
|
||||
-- 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');
|
||||
|
||||
loadstore1_0: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
r <= rin;
|
||||
end if;
|
||||
end process;
|
||||
loadstore1_0: process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
r <= rin;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
loadstore1_1: process(all)
|
||||
variable v : Loadstore1ToLoadstore2Type;
|
||||
begin
|
||||
v := r;
|
||||
loadstore1_1: process(all)
|
||||
variable v : Loadstore1ToLoadstore2Type;
|
||||
begin
|
||||
v := r;
|
||||
|
||||
v.valid := l_in.valid;
|
||||
v.load := l_in.load;
|
||||
v.data := l_in.data;
|
||||
v.write_reg := l_in.write_reg;
|
||||
v.length := l_in.length;
|
||||
v.byte_reverse := l_in.byte_reverse;
|
||||
v.sign_extend := l_in.sign_extend;
|
||||
v.update := l_in.update;
|
||||
v.update_reg := l_in.update_reg;
|
||||
v.valid := l_in.valid;
|
||||
v.load := l_in.load;
|
||||
v.data := l_in.data;
|
||||
v.write_reg := l_in.write_reg;
|
||||
v.length := l_in.length;
|
||||
v.byte_reverse := l_in.byte_reverse;
|
||||
v.sign_extend := l_in.sign_extend;
|
||||
v.update := l_in.update;
|
||||
v.update_reg := l_in.update_reg;
|
||||
|
||||
-- byte reverse stores in the first cycle
|
||||
if v.load = '0' and l_in.byte_reverse = '1' then
|
||||
v.data := byte_reverse(l_in.data, to_integer(unsigned(l_in.length)));
|
||||
end if;
|
||||
-- byte reverse stores in the first cycle
|
||||
if v.load = '0' and l_in.byte_reverse = '1' then
|
||||
v.data := byte_reverse(l_in.data, to_integer(unsigned(l_in.length)));
|
||||
end if;
|
||||
|
||||
v.addr := lsu_sum;
|
||||
v.addr := lsu_sum;
|
||||
|
||||
-- Update registers
|
||||
rin <= v;
|
||||
-- Update registers
|
||||
rin <= v;
|
||||
|
||||
-- Update outputs
|
||||
l_out <= r;
|
||||
end process;
|
||||
-- Update outputs
|
||||
l_out <= r;
|
||||
end process;
|
||||
end;
|
||||
|
||||
243
loadstore2.vhdl
243
loadstore2.vhdl
@ -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.
|
||||
|
||||
entity loadstore2 is
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
|
||||
l_in : in Loadstore1ToLoadstore2Type;
|
||||
w_out : out Loadstore2ToWritebackType;
|
||||
l_in : in Loadstore1ToLoadstore2Type;
|
||||
w_out : out Loadstore2ToWritebackType;
|
||||
|
||||
m_in : in wishbone_slave_out;
|
||||
m_out : out wishbone_master_out
|
||||
);
|
||||
m_in : in wishbone_slave_out;
|
||||
m_out : out wishbone_master_out
|
||||
);
|
||||
end loadstore2;
|
||||
|
||||
architecture behave of loadstore2 is
|
||||
signal l_saved : Loadstore1ToLoadstore2Type;
|
||||
signal w_tmp : Loadstore2ToWritebackType;
|
||||
signal m_tmp : wishbone_master_out;
|
||||
signal l_saved : Loadstore1ToLoadstore2Type;
|
||||
signal w_tmp : Loadstore2ToWritebackType;
|
||||
signal m_tmp : wishbone_master_out;
|
||||
|
||||
type state_t is (IDLE, WAITING_FOR_READ_ACK, WAITING_FOR_WRITE_ACK);
|
||||
signal state : state_t := IDLE;
|
||||
type state_t is (IDLE, WAITING_FOR_READ_ACK, WAITING_FOR_WRITE_ACK);
|
||||
signal state : state_t := IDLE;
|
||||
|
||||
function length_to_sel(length : in std_logic_vector(3 downto 0)) return std_ulogic_vector is
|
||||
begin
|
||||
case length is
|
||||
when "0001" =>
|
||||
return "00000001";
|
||||
when "0010" =>
|
||||
return "00000011";
|
||||
when "0100" =>
|
||||
return "00001111";
|
||||
when "1000" =>
|
||||
return "11111111";
|
||||
when others =>
|
||||
return "00000000";
|
||||
end case;
|
||||
end function length_to_sel;
|
||||
function length_to_sel(length : in std_logic_vector(3 downto 0)) return std_ulogic_vector is
|
||||
begin
|
||||
case length is
|
||||
when "0001" =>
|
||||
return "00000001";
|
||||
when "0010" =>
|
||||
return "00000011";
|
||||
when "0100" =>
|
||||
return "00001111";
|
||||
when "1000" =>
|
||||
return "11111111";
|
||||
when others =>
|
||||
return "00000000";
|
||||
end case;
|
||||
end function length_to_sel;
|
||||
|
||||
function wishbone_data_shift(address : in std_ulogic_vector(63 downto 0)) return natural is
|
||||
begin
|
||||
return to_integer(unsigned(address(2 downto 0))) * 8;
|
||||
end function wishbone_data_shift;
|
||||
function wishbone_data_shift(address : in std_ulogic_vector(63 downto 0)) return natural is
|
||||
begin
|
||||
return to_integer(unsigned(address(2 downto 0))) * 8;
|
||||
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
|
||||
begin
|
||||
return std_ulogic_vector(shift_left(unsigned(length_to_sel(size)), to_integer(unsigned(address(2 downto 0)))));
|
||||
end function wishbone_data_sel;
|
||||
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
|
||||
return std_ulogic_vector(shift_left(unsigned(length_to_sel(size)), to_integer(unsigned(address(2 downto 0)))));
|
||||
end function wishbone_data_sel;
|
||||
begin
|
||||
w_out <= w_tmp;
|
||||
m_out <= m_tmp;
|
||||
w_out <= w_tmp;
|
||||
m_out <= m_tmp;
|
||||
|
||||
loadstore2_0: process(clk)
|
||||
variable tmp : std_ulogic_vector(63 downto 0);
|
||||
variable data : std_ulogic_vector(63 downto 0);
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
tmp := (others => '0');
|
||||
data := (others => '0');
|
||||
loadstore2_0: process(clk)
|
||||
variable tmp : std_ulogic_vector(63 downto 0);
|
||||
variable data : std_ulogic_vector(63 downto 0);
|
||||
variable sign_extend_byte_reverse : std_ulogic_vector(1 downto 0);
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
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 =>
|
||||
if l_in.valid = '1' then
|
||||
m_tmp <= wishbone_master_out_init;
|
||||
case_0: case state is
|
||||
when IDLE =>
|
||||
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.cyc <= '1';
|
||||
m_tmp.stb <= '1';
|
||||
m_tmp.sel <= wishbone_data_sel(l_in.length, l_in.addr);
|
||||
m_tmp.adr <= l_in.addr(63 downto 3) & "000";
|
||||
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
|
||||
-- single in the pipeline and write back the update GPR now
|
||||
-- and the load once we get the data back. We'll have to
|
||||
-- revisit this when loads can take exceptions.
|
||||
if l_in.update = '1' then
|
||||
w_tmp.write_enable <= '1';
|
||||
w_tmp.write_reg <= l_in.update_reg;
|
||||
w_tmp.write_data <= l_in.addr;
|
||||
end if;
|
||||
-- Load with update instructions write two GPR destinations.
|
||||
-- We don't want the expense of two write ports, so make it
|
||||
-- single in the pipeline and write back the update GPR now
|
||||
-- and the load once we get the data back. We'll have to
|
||||
-- revisit this when loads can take exceptions.
|
||||
if l_in.update = '1' then
|
||||
w_tmp.write_enable <= '1';
|
||||
w_tmp.write_reg <= l_in.update_reg;
|
||||
w_tmp.write_data <= l_in.addr;
|
||||
end if;
|
||||
|
||||
state <= WAITING_FOR_READ_ACK;
|
||||
else
|
||||
m_tmp.we <= '1';
|
||||
state <= WAITING_FOR_READ_ACK;
|
||||
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;
|
||||
end if;
|
||||
state <= WAITING_FOR_WRITE_ACK;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when WAITING_FOR_READ_ACK =>
|
||||
if m_in.ack = '1' then
|
||||
tmp := std_logic_vector(shift_right(unsigned(m_in.dat), wishbone_data_shift(l_saved.addr)));
|
||||
case to_integer(unsigned(l_saved.length)) is
|
||||
when 0 =>
|
||||
when 1 =>
|
||||
data(7 downto 0) := tmp(7 downto 0);
|
||||
when 2 =>
|
||||
data(15 downto 0) := tmp(15 downto 0);
|
||||
when 4 =>
|
||||
data(31 downto 0) := tmp(31 downto 0);
|
||||
when 8 =>
|
||||
data(63 downto 0) := tmp(63 downto 0);
|
||||
when others =>
|
||||
assert false report "invalid length" severity failure;
|
||||
end case;
|
||||
when WAITING_FOR_READ_ACK =>
|
||||
if m_in.ack = '1' then
|
||||
tmp := std_logic_vector(shift_right(unsigned(m_in.dat), wishbone_data_shift(l_saved.addr)));
|
||||
case to_integer(unsigned(l_saved.length)) is
|
||||
when 0 =>
|
||||
when 1 =>
|
||||
data(7 downto 0) := tmp(7 downto 0);
|
||||
when 2 =>
|
||||
data(15 downto 0) := tmp(15 downto 0);
|
||||
when 4 =>
|
||||
data(31 downto 0) := tmp(31 downto 0);
|
||||
when 8 =>
|
||||
data(63 downto 0) := tmp(63 downto 0);
|
||||
when others =>
|
||||
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)));
|
||||
end if;
|
||||
sign_extend_byte_reverse := l_saved.sign_extend & l_saved.byte_reverse;
|
||||
|
||||
if l_saved.byte_reverse = '1' then
|
||||
data := byte_reverse(data, to_integer(unsigned(l_saved.length)));
|
||||
end if;
|
||||
case sign_extend_byte_reverse is
|
||||
when "10" =>
|
||||
data := sign_extend(data, to_integer(unsigned(l_saved.length)));
|
||||
when "01" =>
|
||||
data := byte_reverse(data, to_integer(unsigned(l_saved.length)));
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
w_tmp.write_data <= data;
|
||||
w_tmp.write_data <= data;
|
||||
|
||||
-- write data to register file
|
||||
w_tmp.valid <= '1';
|
||||
w_tmp.write_enable <= '1';
|
||||
w_tmp.write_reg <= l_saved.write_reg;
|
||||
-- write data to register file
|
||||
w_tmp.valid <= '1';
|
||||
w_tmp.write_enable <= '1';
|
||||
w_tmp.write_reg <= l_saved.write_reg;
|
||||
|
||||
m_tmp <= wishbone_master_out_init;
|
||||
state <= IDLE;
|
||||
end if;
|
||||
m_tmp <= wishbone_master_out_init;
|
||||
state <= IDLE;
|
||||
end if;
|
||||
|
||||
when WAITING_FOR_WRITE_ACK =>
|
||||
if m_in.ack = '1' then
|
||||
w_tmp.valid <= '1';
|
||||
if l_saved.update = '1' then
|
||||
w_tmp.write_enable <= '1';
|
||||
w_tmp.write_reg <= l_saved.update_reg;
|
||||
w_tmp.write_data <= l_saved.addr;
|
||||
end if;
|
||||
when WAITING_FOR_WRITE_ACK =>
|
||||
if m_in.ack = '1' then
|
||||
w_tmp.valid <= '1';
|
||||
if l_saved.update = '1' then
|
||||
w_tmp.write_enable <= '1';
|
||||
w_tmp.write_reg <= l_saved.update_reg;
|
||||
w_tmp.write_data <= l_saved.addr;
|
||||
end if;
|
||||
|
||||
m_tmp <= wishbone_master_out_init;
|
||||
state <= IDLE;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end process;
|
||||
m_tmp <= wishbone_master_out_init;
|
||||
state <= IDLE;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end process;
|
||||
end;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user