forked from antonblanchard/microwatt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxics.vhdl
218 lines (191 loc) · 6.27 KB
/
xics.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
--
-- This is a simple XICS compliant interrupt controller. This is a
-- Presenter (ICP) and Source (ICS) in a single unit with no routing
-- layer.
--
-- The sources have a fixed IRQ priority set by HW_PRIORITY. The
-- source id starts at 16 for int_level_in(0) and go up from
-- there (ie int_level_in(1) is source id 17).
--
-- The presentation layer will pick an interupt that is more
-- favourable than the current CPPR and present it via the XISR and
-- send an interrpt to the processor (via e_out). This may not be the
-- highest priority interrupt currently presented (which is allowed
-- via XICS)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.common.all;
use work.wishbone_types.all;
entity xics is
generic (
LEVEL_NUM : positive := 16
);
port (
clk : in std_logic;
rst : in std_logic;
wb_in : in wb_io_master_out;
wb_out : out wb_io_slave_out;
int_level_in : in std_ulogic_vector(LEVEL_NUM - 1 downto 0);
core_irq_out : out std_ulogic
);
end xics;
architecture behaviour of xics is
type reg_internal_t is record
xisr : std_ulogic_vector(23 downto 0);
cppr : std_ulogic_vector(7 downto 0);
pending_priority : std_ulogic_vector(7 downto 0);
mfrr : std_ulogic_vector(7 downto 0);
mfrr_pending : std_ulogic;
irq : std_ulogic;
wb_rd_data : std_ulogic_vector(31 downto 0);
wb_ack : std_ulogic;
end record;
constant reg_internal_init : reg_internal_t :=
(wb_ack => '0',
mfrr_pending => '0',
mfrr => x"00", -- mask everything on reset
irq => '0',
others => (others => '0'));
signal r, r_next : reg_internal_t;
-- hardwire the hardware IRQ priority
constant HW_PRIORITY : std_ulogic_vector(7 downto 0) := x"80";
-- 8 bit offsets for each presentation
constant XIRR_POLL : std_ulogic_vector(7 downto 0) := x"00";
constant XIRR : std_ulogic_vector(7 downto 0) := x"04";
constant RESV0 : std_ulogic_vector(7 downto 0) := x"08";
constant MFRR : std_ulogic_vector(7 downto 0) := x"0c";
begin
regs : process(clk)
begin
if rising_edge(clk) then
r <= r_next;
end if;
end process;
wb_out.dat <= r.wb_rd_data;
wb_out.ack <= r.wb_ack;
wb_out.stall <= '0'; -- never stall wishbone
core_irq_out <= r.irq;
comb : process(all)
variable v : reg_internal_t;
variable xirr_accept_rd : std_ulogic;
variable irq_eoi : std_ulogic;
begin
v := r;
v.wb_ack := '0';
xirr_accept_rd := '0';
irq_eoi := '0';
if wb_in.cyc = '1' and wb_in.stb = '1' then
v.wb_ack := '1'; -- always ack
if wb_in.we = '1' then -- write
-- writes to both XIRR are the same
case wb_in.adr(7 downto 0) is
when XIRR_POLL =>
report "XICS XIRR_POLL write";
if wb_in.sel = x"f" then -- 4 bytes
v.cppr := wb_in.dat(31 downto 24);
elsif wb_in.sel = x"1" then -- 1 byte
v.cppr := wb_in.dat(7 downto 0);
end if;
when XIRR =>
if wb_in.sel = x"f" then -- 4 byte
report "XICS XIRR write word:" & to_hstring(wb_in.dat);
v.cppr := wb_in.dat(31 downto 24);
irq_eoi := '1';
elsif wb_in.sel = x"1" then -- 1 byte
report "XICS XIRR write byte:" & to_hstring(wb_in.dat(7 downto 0));
v.cppr := wb_in.dat(7 downto 0);
else
report "XICS XIRR UNSUPPORTED write ! sel=" & to_hstring(wb_in.sel);
end if;
when MFRR =>
if wb_in.sel = x"f" then -- 4 bytes
report "XICS MFRR write word:" & to_hstring(wb_in.dat);
v.mfrr_pending := '1';
v.mfrr := wb_in.dat(31 downto 24);
elsif wb_in.sel = x"1" then -- 1 byte
report "XICS MFRR write byte:" & to_hstring(wb_in.dat(7 downto 0));
v.mfrr_pending := '1';
v.mfrr := wb_in.dat(7 downto 0);
else
report "XICS MFRR UNSUPPORTED write ! sel=" & to_hstring(wb_in.sel);
end if;
when others =>
end case;
else -- read
v.wb_rd_data := (others => '0');
case wb_in.adr(7 downto 0) is
when XIRR_POLL =>
report "XICS XIRR_POLL read";
if wb_in.sel = x"f" then
v.wb_rd_data(23 downto 0) := r.xisr;
v.wb_rd_data(31 downto 24) := r.cppr;
elsif wb_in.sel = x"1" then
v.wb_rd_data(7 downto 0) := r.cppr;
end if;
when XIRR =>
report "XICS XIRR read";
if wb_in.sel = x"f" then
v.wb_rd_data(23 downto 0) := r.xisr;
v.wb_rd_data(31 downto 24) := r.cppr;
xirr_accept_rd := '1';
elsif wb_in.sel = x"1" then
v.wb_rd_data(7 downto 0) := r.cppr;
end if;
when MFRR =>
report "XICS MFRR read";
if wb_in.sel = x"f" then -- 4 bytes
v.wb_rd_data(31 downto 24) := r.mfrr;
elsif wb_in.sel = x"1" then -- 1 byte
v.wb_rd_data( 7 downto 0) := r.mfrr;
end if;
when others =>
end case;
end if;
end if;
-- generate interrupt
if r.irq = '0' then
-- Here we just present any interrupt that's valid and
-- below cppr. For ordering, we ignore hardware
-- priorities.
if unsigned(HW_PRIORITY) < unsigned(r.cppr) then --
-- lower HW sources are higher priority
for i in LEVEL_NUM - 1 downto 0 loop
if int_level_in(i) = '1' then
v.irq := '1';
v.xisr := std_ulogic_vector(to_unsigned(16 + i, 24));
v.pending_priority := HW_PRIORITY; -- hardware HW IRQs
end if;
end loop;
end if;
-- Do mfrr as a higher priority so mfrr_pending is cleared
if unsigned(r.mfrr) < unsigned(r.cppr) then --
report "XICS: MFRR INTERRUPT";
-- IPI
if r.mfrr_pending = '1' then
v.irq := '1';
v.xisr := x"000002"; -- special XICS MFRR IRQ source number
v.pending_priority := r.mfrr;
v.mfrr_pending := '0';
end if;
end if;
end if;
-- Accept the interrupt
if xirr_accept_rd = '1' then
report "XICS: ACCEPT" &
" cppr:" & to_hstring(r.cppr) &
" xisr:" & to_hstring(r.xisr) &
" mfrr:" & to_hstring(r.mfrr);
v.cppr := r.pending_priority;
end if;
if irq_eoi = '1' then
v.irq := '0';
end if;
if rst = '1' then
v := reg_internal_init;
end if;
r_next <= v;
end process;
end architecture behaviour;