forked from antonblanchard/microwatt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathloadstore2.vhdl
151 lines (120 loc) · 3.98 KB
/
loadstore2.vhdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.common.all;
use work.helpers.all;
use work.wishbone_types.all;
-- 2 cycle LSU
-- 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;
l_in : in Loadstore1ToLoadstore2Type;
w_out : out Loadstore2ToWritebackType;
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;
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 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;
begin
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');
w_tmp <= Loadstore2ToWritebackInit;
l_saved <= l_saved;
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';
if l_in.load = '1' then
m_tmp.we <= '0';
l_saved <= l_in;
state <= WAITING_FOR_READ_ACK;
else
m_tmp.we <= '1';
w_tmp.valid <= '1';
data := l_in.data;
if l_in.byte_reverse = '1' then
data := byte_reverse(data, to_integer(unsigned(l_in.length)));
end if;
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;
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_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)));
data((to_integer(unsigned(l_saved.length))*8-1) downto 0) := tmp((to_integer(unsigned(l_saved.length))*8-1) downto 0);
if l_saved.sign_extend = '1' then
data := sign_extend(data, to_integer(unsigned(l_saved.length)));
end if;
if l_saved.byte_reverse = '1' then
data := byte_reverse(data, to_integer(unsigned(l_saved.length)));
end if;
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;
if l_saved.update = '1' then
w_tmp.write_enable2 <= '1';
w_tmp.write_reg2 <= l_saved.update_reg;
w_tmp.write_data2 <= l_saved.addr;
end if;
m_tmp <= wishbone_master_out_init;
state <= IDLE;
end if;
when WAITING_FOR_WRITE_ACK =>
if m_in.ack = '1' then
m_tmp <= wishbone_master_out_init;
state <= IDLE;
end if;
end case;
end if;
end process;
end;