Edge sensitive IRQ on UART
[mw/milkymist.git] / cores / sysctl / rtl / sysctl.v
1 /*
2  * Milkymist VJ SoC
3  * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 module sysctl #(
19         parameter csr_addr = 4'h0,
20         parameter ninputs = 16,
21         parameter noutputs = 16,
22         parameter systemid = 32'habadface
23 ) (
24         input sys_clk,
25         input sys_rst,
26         
27         /* Interrupts */
28         output reg gpio_irq,
29         output reg timer0_irq,
30         output reg timer1_irq,
31
32         /* CSR bus interface */
33         input [13:0] csr_a,
34         input csr_we,
35         input [31:0] csr_di,
36         output reg [31:0] csr_do,
37         
38         /* GPIO */
39         input [ninputs-1:0] gpio_inputs,
40         output reg [noutputs-1:0] gpio_outputs
41 );
42
43 /*
44  * GPIO
45  */
46
47 /* Synchronize the input */
48 reg [ninputs-1:0] gpio_in0;
49 reg [ninputs-1:0] gpio_in;
50 always @(posedge sys_clk) begin
51         gpio_in0 <= gpio_inputs;
52         gpio_in <= gpio_in0;
53 end
54
55 /* Detect level changes and generate IRQs */
56 reg [ninputs-1:0] gpio_inbefore;
57 always @(posedge sys_clk) gpio_inbefore <= gpio_in;
58 wire [ninputs-1:0] gpio_diff = gpio_inbefore ^ gpio_in;
59 reg [ninputs-1:0] gpio_irqen;
60 always @(posedge sys_clk) begin
61         if(sys_rst)
62                 gpio_irq <= 1'b0;
63         else
64                 gpio_irq <= |(gpio_diff & gpio_irqen);
65 end
66
67 /*
68  * Dual timer
69  */
70
71 reg trig0, trig1;
72 reg en0, en1;
73 reg ar0, ar1;
74 reg [31:0] counter0, counter1;
75 reg [31:0] compare0, compare1;
76
77 wire match0 = (counter0 == compare0);
78 wire match1 = (counter1 == compare1);
79
80 /*
81  * Logic and CSR interface
82  */
83
84 wire csr_selected = csr_a[13:10] == csr_addr;
85
86 always @(posedge sys_clk) begin
87         if(sys_rst) begin
88                 csr_do <= 32'd0;
89
90                 timer0_irq <= 1'b0;
91                 timer1_irq <= 1'b0;
92         
93                 gpio_outputs <= {noutputs{1'b0}};
94                 gpio_irqen <= {ninputs{1'b0}};
95                 
96                 en0 <= 1'b0;
97                 en1 <= 1'b0;
98                 ar0 <= 1'b0;
99                 ar1 <= 1'b0;
100                 trig0 <= 1'b0;
101                 trig1 <= 1'b0;
102                 counter0 <= 32'd0;
103                 counter1 <= 32'd0;
104                 compare0 <= 32'hFFFFFFFF;
105                 compare1 <= 32'hFFFFFFFF;
106         end else begin
107                 timer0_irq <= 1'b0;
108                 timer1_irq <= 1'b0;
109
110                 /* Handle timer 0 */
111                 if( en0 & ~match0) counter0 <= counter0 + 32'd1;
112                 if( en0 &  match0) begin
113                         trig0 <= 1'b1;
114                         timer0_irq <= 1'b1;
115                 end
116                 if( ar0 &  match0) counter0 <= 32'd1;
117                 if(~ar0 &  match0) en0 <= 1'b0;
118
119                 /* Handle timer 1 */
120                 if( en1 & ~match1) counter1 <= counter1 + 32'd1;
121                 if( en1 &  match1) begin
122                         trig1 <= 1'b1;
123                         timer1_irq <= 1'b1;
124                 end
125                 if( ar1 &  match1) counter1 <= 32'd1;
126                 if(~ar1 &  match1) en1 <= 1'b0;
127         
128                 csr_do <= 32'd0;
129                 if(csr_selected) begin
130                         /* CSR Writes */
131                         if(csr_we) begin
132                                 case(csr_a[3:0])
133                                         /* GPIO registers */
134                                         // 0000 is GPIO IN and is read-only
135                                         4'b0001: gpio_outputs <= csr_di[noutputs-1:0];
136                                         4'b0010: gpio_irqen <= csr_di[ninputs-1:0];
137                                         
138                                         /* Timer 0 registers */
139                                         4'b0100: begin
140                                                 trig0 <= 1'b0;
141                                                 ar0 <= csr_di[1];
142                                                 en0 <= csr_di[2];
143                                         end
144                                         4'b0101: compare0 <= csr_di;
145                                         4'b0110: counter0 <= csr_di;
146                                         
147                                         /* Timer 1 registers */
148                                         4'b1000: begin
149                                                 trig1 <= 1'b0;
150                                                 ar1 <= csr_di[1];
151                                                 en1 <= csr_di[2];
152                                         end
153                                         4'b1001: compare1 <= csr_di;
154                                         4'b1010: counter1 <= csr_di;
155                                 endcase
156                         end
157                 
158                         /* CSR Reads */
159                         case(csr_a[3:0])
160                                 /* GPIO registers */
161                                 4'b0000: csr_do <= gpio_in;
162                                 4'b0001: csr_do <= gpio_outputs;
163                                 4'b0010: csr_do <= gpio_irqen;
164                                 
165                                 /* Timer 0 registers */
166                                 4'b0100: csr_do <= {en0, ar0, trig0};
167                                 4'b0101: csr_do <= compare0;
168                                 4'b0110: csr_do <= counter0;
169                                 
170                                 /* Timer 1 registers */
171                                 4'b1000: csr_do <= {en1, ar1, trig1};
172                                 4'b1001: csr_do <= compare1;
173                                 4'b1010: csr_do <= counter1;
174                                 
175                                 4'b1111: csr_do <= systemid;
176                         endcase
177                 end
178         end
179 end
180
181 endmodule