forked from ZipCPU/zipcpu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathicontrol.v
146 lines (138 loc) · 5.11 KB
/
icontrol.v
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
////////////////////////////////////////////////////////////////////////////////
//
// Filename: icontrol.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: An interrupt controller, for managing many interrupt sources.
//
// This interrupt controller started from the question of how best to
// design a simple interrupt controller. As such, it has a few nice
// qualities to it:
// 1. This is wishbone compliant
// 2. It sits on a 32-bit wishbone data bus
// 3. It only consumes one address on that wishbone bus.
// 4. There is no extra delays associated with reading this
// device.
// 5. Common operations can all be done in one clock.
//
// So, how shall this be used? First, the 32-bit word is broken down as
// follows:
//
// Bit 31 - This is the global interrupt enable bit. If set, interrupts
// will be generated and passed on as they come in.
// Bits 16-30 - These are specific interrupt enable lines. If set,
// interrupts from source (bit#-16) will be enabled.
// To set this line and enable interrupts from this source, write
// to the register with this bit set and the global enable set.
// To disable this line, write to this register with global enable
// bit not set, but this bit set. (Writing a zero to any of these
// bits has no effect, either setting or unsetting them.)
// Bit 15 - This is the any interrupt pin. If any interrupt is pending,
// this bit will be set.
// Bits 0-14 - These are interrupt bits. When set, an interrupt is
// pending from the corresponding source--regardless of whether
// it was enabled. (If not enabled, it won't generate an
// interrupt, but it will still register here.) To clear any
// of these bits, write a '1' to the corresponding bit. Writing
// a zero to any of these bits has no effect.
//
// The peripheral also sports a parameter, IUSED, which can be set
// to any value between 1 and (buswidth/2-1, or) 15 inclusive. This will
// be the number of interrupts handled by this routine. (Without the
// parameter, Vivado was complaining about unused bits. With it, we can
// keep the complaints down and still use the routine).
//
// To get access to more than 15 interrupts, chain these together, so
// that one interrupt controller device feeds another.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
//
module icontrol(i_clk, i_reset, i_wr, i_proc_bus, o_proc_bus,
i_brd_ints, o_interrupt);
parameter IUSED = 15;
input wire i_clk, i_reset;
input wire i_wr;
input wire [31:0] i_proc_bus;
output wire [31:0] o_proc_bus;
input wire [(IUSED-1):0] i_brd_ints;
output wire o_interrupt;
reg [(IUSED-1):0] r_int_state;
reg [(IUSED-1):0] r_int_enable;
wire [(IUSED-1):0] nxt_int_state;
reg r_any, r_interrupt, r_gie;
assign nxt_int_state = (r_int_state|i_brd_ints);
initial r_int_state = 0;
always @(posedge i_clk)
if (i_reset)
r_int_state <= 0;
else if (i_wr)
r_int_state <= nxt_int_state & (~i_proc_bus[(IUSED-1):0]);
else
r_int_state <= nxt_int_state;
initial r_int_enable = 0;
always @(posedge i_clk)
if (i_reset)
r_int_enable <= 0;
else if ((i_wr)&&(i_proc_bus[31]))
r_int_enable <= r_int_enable | i_proc_bus[(16+IUSED-1):16];
else if ((i_wr)&&(~i_proc_bus[31]))
r_int_enable <= r_int_enable & (~ i_proc_bus[(16+IUSED-1):16]);
initial r_gie = 1'b0;
always @(posedge i_clk)
if (i_reset)
r_gie <= 1'b0;
else if (i_wr)
r_gie <= i_proc_bus[31];
initial r_any = 1'b0;
always @(posedge i_clk)
r_any <= ((r_int_state & r_int_enable) != 0);
initial r_interrupt = 1'b0;
always @(posedge i_clk)
r_interrupt <= r_gie & r_any;
generate
if (IUSED < 15)
begin
assign o_proc_bus = {
r_gie, { {(15-IUSED){1'b0}}, r_int_enable },
r_any, { {(15-IUSED){1'b0}}, r_int_state } };
end else begin
assign o_proc_bus = { r_gie, r_int_enable, r_any, r_int_state };
end endgenerate
assign o_interrupt = r_interrupt;
// Make verilator happy
// verilator lint_off UNUSED
wire [31:0] unused;
assign unused = i_proc_bus[31:0];
// verilator lint_on UNUSED
endmodule