5690287d68e5706d9842afaf4f5eee8a1344dfc1
[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 assign timer0_irq = trig0;
81 assign timer1_irq = trig1;
82
83 /*
84  * Logic and CSR interface
85  */
86
87 wire csr_selected = csr_a[13:10] == csr_addr;
88
89 always @(posedge sys_clk) begin
90         if(sys_rst) begin
91                 csr_do <= 32'd0;
92
93                 timer0_irq <= 1'b0;
94                 timer1_irq <= 1'b0;
95         
96                 gpio_outputs <= {noutputs{1'b0}};
97                 gpio_irqen <= {ninputs{1'b0}};
98                 
99                 en0 <= 1'b0;
100                 en1 <= 1'b0;
101                 ar0 <= 1'b0;
102                 ar1 <= 1'b0;
103                 trig0 <= 1'b0;
104                 trig1 <= 1'b0;
105                 counter0 <= 32'd0;
106                 counter1 <= 32'd0;
107                 compare0 <= 32'hFFFFFFFF;
108                 compare1 <= 32'hFFFFFFFF;
109         end else begin
110                 timer0_irq <= 1'b0;
111                 timer1_irq <= 1'b0;
112
113                 /* Handle timer 0 */
114                 if( en0 & ~match0) counter0 <= counter0 + 32'd1;
115                 if( en0 &  match0) begin
116                         trig0 <= 1'b1;
117                         timer0_irq <= 1'b1;
118                 end
119                 if( ar0 &  match0) counter0 <= 32'd1;
120                 if(~ar0 &  match0) en0 <= 1'b0;
121
122                 /* Handle timer 1 */
123                 if( en1 & ~match1) counter1 <= counter1 + 32'd1;
124                 if( en1 &  match1) begin
125                         trig1 <= 1'b1;
126                         timer1_irq <= 1'b1;
127                 end
128                 if( ar1 &  match1) counter1 <= 32'd1;
129                 if(~ar1 &  match1) en1 <= 1'b0;
130         
131                 csr_do <= 32'd0;
132                 if(csr_selected) begin
133                         /* CSR Writes */
134                         if(csr_we) begin
135                                 case(csr_a[3:0])
136                                         /* GPIO registers */
137                                         // 0000 is GPIO IN and is read-only
138                                         4'b0001: gpio_outputs <= csr_di[noutputs-1:0];
139                                         4'b0010: gpio_irqen <= csr_di[ninputs-1:0];
140                                         
141                                         /* Timer 0 registers */
142                                         4'b0100: begin
143                                                 trig0 <= 1'b0;
144                                                 ar0 <= csr_di[1];
145                                                 en0 <= csr_di[2];
146                                         end
147                                         4'b0101: compare0 <= csr_di;
148                                         4'b0110: counter0 <= csr_di;
149                                         
150                                         /* Timer 1 registers */
151                                         4'b1000: begin
152                                                 trig1 <= 1'b0;
153                                                 ar1 <= csr_di[1];
154                                                 en1 <= csr_di[2];
155                                         end
156                                         4'b1001: compare1 <= csr_di;
157                                         4'b1010: counter1 <= csr_di;
158                                 endcase
159                         end
160                 
161                         /* CSR Reads */
162                         case(csr_a[3:0])
163                                 /* GPIO registers */
164                                 4'b0000: csr_do <= gpio_in;
165                                 4'b0001: csr_do <= gpio_outputs;
166                                 4'b0010: csr_do <= gpio_irqen;
167                                 
168                                 /* Timer 0 registers */
169                                 4'b0100: csr_do <= {en0, ar0, trig0};
170                                 4'b0101: csr_do <= compare0;
171                                 4'b0110: csr_do <= counter0;
172                                 
173                                 /* Timer 1 registers */
174                                 4'b1000: csr_do <= {en1, ar1, trig1};
175                                 4'b1001: csr_do <= compare1;
176                                 4'b1010: csr_do <= counter1;
177                                 
178                                 4'b1111: csr_do <= systemid;
179                         endcase
180                 end
181         end
182 end
183
184 endmodule