1 |
21 |
dgisselq |
////////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//
|
3 |
|
|
// Filename: icontrol.v
|
4 |
|
|
//
|
5 |
|
|
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
|
6 |
|
|
//
|
7 |
|
|
// Purpose: An interrupt controller, for managing many interrupt sources.
|
8 |
|
|
//
|
9 |
|
|
// This interrupt controller started from the question of how best to
|
10 |
|
|
// design a simple interrupt controller. As such, it has a few nice
|
11 |
|
|
// qualities to it:
|
12 |
|
|
// 1. This is wishbone compliant
|
13 |
|
|
// 2. It sits on a 32-bit wishbone data bus
|
14 |
|
|
// 3. It only consumes one address on that wishbone bus.
|
15 |
|
|
// 4. There is no extra delays associated with reading this
|
16 |
|
|
// device.
|
17 |
|
|
// 5. Common operations can all be done in one clock.
|
18 |
|
|
//
|
19 |
|
|
// So, how shall this be used? First, the 32-bit word is broken down as
|
20 |
|
|
// follows:
|
21 |
|
|
//
|
22 |
|
|
// Bit 31 - This is the global interrupt enable bit. If set, interrupts
|
23 |
|
|
// will be generated and passed on as they come in.
|
24 |
|
|
// Bits 16-30 - These are specific interrupt enable lines. If set,
|
25 |
|
|
// interrupts from source (bit#-16) will be enabled.
|
26 |
|
|
// To set this line and enable interrupts from this source, write
|
27 |
|
|
// to the register with this bit set and the global enable set.
|
28 |
|
|
// To disable this line, write to this register with global enable
|
29 |
|
|
// bit not set, but this bit set. (Writing a zero to any of these
|
30 |
|
|
// bits has no effect, either setting or unsetting them.)
|
31 |
|
|
// Bit 15 - This is the any interrupt pin. If any interrupt is pending,
|
32 |
|
|
// this bit will be set.
|
33 |
|
|
// Bits 0-14 - These are interrupt bits. When set, an interrupt is
|
34 |
|
|
// pending from the corresponding source--regardless of whether
|
35 |
|
|
// it was enabled. (If not enabled, it won't generate an
|
36 |
|
|
// interrupt, but it will still register here.) To clear any
|
37 |
|
|
// of these bits, write a '1' to the corresponding bit. Writing
|
38 |
|
|
// a zero to any of these bits has no effect.
|
39 |
|
|
//
|
40 |
|
|
// The peripheral also sports a parameter, IUSED, which can be set
|
41 |
|
|
// to any value between 1 and (buswidth/2-1, or) 15 inclusive. This will
|
42 |
|
|
// be the number of interrupts handled by this routine. (Without the
|
43 |
|
|
// parameter, Vivado was complaining about unused bits. With it, we can
|
44 |
|
|
// keep the complaints down and still use the routine).
|
45 |
|
|
//
|
46 |
|
|
// To get access to more than 15 interrupts, chain these together, so
|
47 |
|
|
// that one interrupt controller device feeds another.
|
48 |
|
|
//
|
49 |
|
|
//
|
50 |
|
|
// Creator: Dan Gisselquist, Ph.D.
|
51 |
|
|
// Gisselquist Technology, LLC
|
52 |
|
|
//
|
53 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
54 |
|
|
//
|
55 |
|
|
// Copyright (C) 2015, Gisselquist Technology, LLC
|
56 |
|
|
//
|
57 |
|
|
// This program is free software (firmware): you can redistribute it and/or
|
58 |
|
|
// modify it under the terms of the GNU General Public License as published
|
59 |
|
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
60 |
|
|
// your option) any later version.
|
61 |
|
|
//
|
62 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
63 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
64 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
65 |
|
|
// for more details.
|
66 |
|
|
//
|
67 |
|
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
68 |
|
|
// http://www.gnu.org/licenses/gpl.html
|
69 |
|
|
//
|
70 |
|
|
//
|
71 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
72 |
|
|
//
|
73 |
|
|
module icontrol(i_clk, i_reset, i_wr, i_proc_bus, o_proc_bus,
|
74 |
|
|
i_brd_ints, o_interrupt);
|
75 |
|
|
parameter IUSED = 15;
|
76 |
|
|
input i_clk, i_reset;
|
77 |
|
|
input i_wr;
|
78 |
|
|
input [31:0] i_proc_bus;
|
79 |
|
|
output wire [31:0] o_proc_bus;
|
80 |
|
|
input [(IUSED-1):0] i_brd_ints;
|
81 |
|
|
output wire o_interrupt;
|
82 |
|
|
|
83 |
|
|
reg [(IUSED-1):0] r_int_state;
|
84 |
|
|
reg [(IUSED-1):0] r_int_enable;
|
85 |
|
|
wire [(IUSED-1):0] nxt_int_state;
|
86 |
|
|
reg r_any, r_interrupt, r_gie;
|
87 |
|
|
|
88 |
|
|
assign nxt_int_state = (r_int_state|i_brd_ints);
|
89 |
|
|
initial r_int_state = 0;
|
90 |
|
|
always @(posedge i_clk)
|
91 |
|
|
if (i_reset)
|
92 |
|
|
r_int_state <= 0;
|
93 |
|
|
else if (i_wr)
|
94 |
|
|
r_int_state <= nxt_int_state & (~i_proc_bus[(IUSED-1):0]);
|
95 |
|
|
else
|
96 |
|
|
r_int_state <= nxt_int_state;
|
97 |
|
|
initial r_int_enable = 0;
|
98 |
|
|
always @(posedge i_clk)
|
99 |
|
|
if (i_reset)
|
100 |
|
|
r_int_enable <= 0;
|
101 |
|
|
else if ((i_wr)&&(i_proc_bus[31]))
|
102 |
|
|
r_int_enable <= r_int_enable | i_proc_bus[(16+IUSED-1):16];
|
103 |
|
|
else if ((i_wr)&&(~i_proc_bus[31]))
|
104 |
|
|
r_int_enable <= r_int_enable & (~ i_proc_bus[(16+IUSED-1):16]);
|
105 |
|
|
|
106 |
|
|
initial r_gie = 1'b0;
|
107 |
|
|
always @(posedge i_clk)
|
108 |
|
|
if (i_reset)
|
109 |
|
|
r_gie <= 1'b0;
|
110 |
|
|
else if (i_wr)
|
111 |
|
|
r_gie <= i_proc_bus[31];
|
112 |
|
|
|
113 |
|
|
initial r_any = 1'b0;
|
114 |
|
|
always @(posedge i_clk)
|
115 |
|
|
r_any <= ((r_int_state & r_int_enable) != 0);
|
116 |
|
|
initial r_interrupt = 1'b0;
|
117 |
|
|
always @(posedge i_clk)
|
118 |
|
|
r_interrupt <= r_gie & r_any;
|
119 |
|
|
|
120 |
|
|
generate
|
121 |
|
|
if (IUSED < 15)
|
122 |
|
|
begin
|
123 |
|
|
assign o_proc_bus = {
|
124 |
|
|
r_gie, { {(15-IUSED){1'b0}}, r_int_enable },
|
125 |
|
|
r_any, { {(15-IUSED){1'b0}}, r_int_state } };
|
126 |
|
|
end else begin
|
127 |
|
|
assign o_proc_bus = { r_gie, r_int_enable, r_any, r_int_state };
|
128 |
|
|
end endgenerate
|
129 |
|
|
|
130 |
|
|
/*
|
131 |
|
|
reg int_condition;
|
132 |
|
|
initial int_condition = 1'b0;
|
133 |
|
|
initial o_interrupt_strobe = 1'b0;
|
134 |
|
|
always @(posedge i_clk)
|
135 |
|
|
if (i_reset)
|
136 |
|
|
begin
|
137 |
|
|
int_condition <= 1'b0;
|
138 |
|
|
o_interrupt_strobe <= 1'b0;
|
139 |
|
|
end else if (~r_interrupt) // This might end up generating
|
140 |
|
|
begin // many, many, (wild many) interrupts
|
141 |
|
|
int_condition <= 1'b0;
|
142 |
|
|
o_interrupt_strobe <= 1'b0;
|
143 |
|
|
end else if ((~int_condition)&&(r_interrupt))
|
144 |
|
|
begin
|
145 |
|
|
int_condition <= 1'b1;
|
146 |
|
|
o_interrupt_strobe <= 1'b1;
|
147 |
|
|
end else
|
148 |
|
|
o_interrupt_strobe <= 1'b0;
|
149 |
|
|
*/
|
150 |
|
|
|
151 |
|
|
assign o_interrupt = r_interrupt;
|
152 |
|
|
|
153 |
|
|
endmodule
|