debug/sim: Make connect/disconnect messages quieter
[microwatt.git] / loadstore2.vhdl
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
4
5 library work;
6 use work.common.all;
7 use work.helpers.all;
8 use work.wishbone_types.all;
9
10 -- 2 cycle LSU
11 -- In this cycle we read or write any data and do sign extension and update if required.
12
13 entity loadstore2 is
14 port (
15 clk : in std_ulogic;
16
17 l_in : in Loadstore1ToLoadstore2Type;
18 w_out : out Loadstore2ToWritebackType;
19
20 m_in : in wishbone_slave_out;
21 m_out : out wishbone_master_out
22 );
23 end loadstore2;
24
25 architecture behave of loadstore2 is
26 signal l_saved : Loadstore1ToLoadstore2Type;
27 signal w_tmp : Loadstore2ToWritebackType;
28 signal m_tmp : wishbone_master_out;
29 signal read_data : std_ulogic_vector(63 downto 0);
30 signal read_data_shift : std_ulogic_vector(2 downto 0);
31 signal sign_extend_byte_reverse: std_ulogic_vector(1 downto 0);
32 signal dlength : std_ulogic_vector(3 downto 0);
33
34 type state_t is (IDLE, WAITING_FOR_READ_ACK, WAITING_FOR_WRITE_ACK);
35 signal state : state_t := IDLE;
36
37 function length_to_sel(length : in std_logic_vector(3 downto 0)) return std_ulogic_vector is
38 begin
39 case length is
40 when "0001" =>
41 return "00000001";
42 when "0010" =>
43 return "00000011";
44 when "0100" =>
45 return "00001111";
46 when "1000" =>
47 return "11111111";
48 when others =>
49 return "00000000";
50 end case;
51 end function length_to_sel;
52
53 function wishbone_data_shift(address : in std_ulogic_vector(63 downto 0)) return natural is
54 begin
55 return to_integer(unsigned(address(2 downto 0))) * 8;
56 end function wishbone_data_shift;
57
58 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
59 begin
60 return std_ulogic_vector(shift_left(unsigned(length_to_sel(size)), to_integer(unsigned(address(2 downto 0)))));
61 end function wishbone_data_sel;
62 begin
63
64 loadstore2_1: process(all)
65 variable tmp : std_ulogic_vector(63 downto 0);
66 variable data : std_ulogic_vector(63 downto 0);
67 begin
68 tmp := std_logic_vector(shift_right(unsigned(read_data), to_integer(unsigned(read_data_shift)) * 8));
69 data := (others => '0');
70 case to_integer(unsigned(dlength)) is
71 when 0 =>
72 when 1 =>
73 data(7 downto 0) := tmp(7 downto 0);
74 when 2 =>
75 data(15 downto 0) := tmp(15 downto 0);
76 when 4 =>
77 data(31 downto 0) := tmp(31 downto 0);
78 when 8 =>
79 data(63 downto 0) := tmp(63 downto 0);
80 when others =>
81 assert false report "invalid length" severity failure;
82 data(63 downto 0) := tmp(63 downto 0);
83 end case;
84
85 case sign_extend_byte_reverse is
86 when "10" =>
87 w_tmp.write_data <= sign_extend(data, to_integer(unsigned(l_saved.length)));
88 when "01" =>
89 w_tmp.write_data <= byte_reverse(data, to_integer(unsigned(l_saved.length)));
90 when others =>
91 w_tmp.write_data <= data;
92 end case;
93 end process;
94
95 w_out <= w_tmp;
96 m_out <= m_tmp;
97
98 loadstore2_0: process(clk)
99 begin
100 if rising_edge(clk) then
101
102 w_tmp.valid <= '0';
103 w_tmp.write_enable <= '0';
104 w_tmp.write_reg <= (others => '0');
105
106 l_saved <= l_saved;
107 read_data_shift <= "000";
108 sign_extend_byte_reverse <= "00";
109 dlength <= "1000";
110
111 case_0: case state is
112 when IDLE =>
113 if l_in.valid = '1' then
114 m_tmp <= wishbone_master_out_init;
115
116 m_tmp.sel <= wishbone_data_sel(l_in.length, l_in.addr);
117 m_tmp.adr <= l_in.addr(63 downto 3) & "000";
118 m_tmp.cyc <= '1';
119 m_tmp.stb <= '1';
120
121 l_saved <= l_in;
122
123 if l_in.load = '1' then
124 m_tmp.we <= '0';
125
126 -- Load with update instructions write two GPR destinations.
127 -- We don't want the expense of two write ports, so make it
128 -- single in the pipeline and write back the update GPR now
129 -- and the load once we get the data back. We'll have to
130 -- revisit this when loads can take exceptions.
131 if l_in.update = '1' then
132 w_tmp.write_enable <= '1';
133 w_tmp.write_reg <= l_in.update_reg;
134 read_data <= l_in.addr;
135 end if;
136
137 state <= WAITING_FOR_READ_ACK;
138 else
139 m_tmp.we <= '1';
140
141 m_tmp.dat <= std_logic_vector(shift_left(unsigned(l_in.data), wishbone_data_shift(l_in.addr)));
142
143 assert l_in.sign_extend = '0' report "sign extension doesn't make sense for stores" severity failure;
144
145 state <= WAITING_FOR_WRITE_ACK;
146 end if;
147 end if;
148
149 when WAITING_FOR_READ_ACK =>
150 if m_in.ack = '1' then
151 read_data <= m_in.dat;
152 read_data_shift <= l_saved.addr(2 downto 0);
153 dlength <= l_saved.length;
154 sign_extend_byte_reverse <= l_saved.sign_extend & l_saved.byte_reverse;
155
156 -- write data to register file
157 w_tmp.valid <= '1';
158 w_tmp.write_enable <= '1';
159 w_tmp.write_reg <= l_saved.write_reg;
160
161 m_tmp <= wishbone_master_out_init;
162 state <= IDLE;
163 end if;
164
165 when WAITING_FOR_WRITE_ACK =>
166 if m_in.ack = '1' then
167 w_tmp.valid <= '1';
168 if l_saved.update = '1' then
169 w_tmp.write_enable <= '1';
170 w_tmp.write_reg <= l_saved.update_reg;
171 read_data <= l_saved.addr;
172 end if;
173
174 m_tmp <= wishbone_master_out_init;
175 state <= IDLE;
176 end if;
177 end case;
178 end if;
179 end process;
180 end;