blob: c543a6b93331460302687c4f7cda8777e199a78a [file] [log] [blame]
agorararmard6c766a82020-12-10 18:13:12 +02001// SPDX-FileCopyrightText: 2020 Efabless Corporation
agorararmarde5780bf2020-12-09 21:27:56 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
agorararmardafa96ea2020-12-09 23:37:31 +020014// SPDX-License-Identifier: Apache-2.0
agorararmarde5780bf2020-12-09 21:27:56 +000015
Matt Venn08cd6eb2020-11-16 12:01:14 +010016`default_nettype none
Tim Edwards7be29a22020-10-25 21:50:19 -040017/* Simple 32-bit counter-timer for Caravel. */
18
19/* Counter acts as low 32 bits of a 64-bit counter
20 * when chained with the other counter.
21 */
22
23module counter_timer_low_wb # (
24 parameter BASE_ADR = 32'h2400_0000,
25 parameter CONFIG = 8'h00,
26 parameter VALUE = 8'h04,
27 parameter DATA = 8'h08
28) (
29 input wb_clk_i,
30 input wb_rst_i,
31 input [31:0] wb_adr_i,
32 input [31:0] wb_dat_i,
33 input [3:0] wb_sel_i,
34 input wb_we_i,
35 input wb_cyc_i,
36 input wb_stb_i,
37
38 output wb_ack_o,
39 output [31:0] wb_dat_o,
40
41 input stop_in,
42 input enable_in,
43 output strobe,
44 output is_offset,
45 output stop_out,
46 output enable_out,
47 output irq
48);
49 wire [31:0] counter_timer_reg_cfg_do;
50 wire [31:0] counter_timer_reg_val_do;
51 wire [31:0] counter_timer_reg_dat_do;
52
53 wire resetn = ~wb_rst_i;
54 wire valid = wb_stb_i && wb_cyc_i;
55 wire counter_timer_reg_cfg_sel = valid && (wb_adr_i == (BASE_ADR | CONFIG));
56 wire counter_timer_reg_val_sel = valid && (wb_adr_i == (BASE_ADR | VALUE));
57 wire counter_timer_reg_dat_sel = valid && (wb_adr_i == (BASE_ADR | DATA));
58
59 wire reg_cfg_we = (counter_timer_reg_cfg_sel) ?
60 (wb_sel_i[0] & {wb_we_i}): 1'b0;
61 wire [3:0] reg_val_we = (counter_timer_reg_val_sel) ?
62 (wb_sel_i & {4{wb_we_i}}): 4'b0000;
63 wire [3:0] reg_dat_we = (counter_timer_reg_dat_sel) ?
64 (wb_sel_i & {4{wb_we_i}}): 4'b0000;
65
66 wire [31:0] mem_wdata = wb_dat_i;
67 wire reg_dat_re = counter_timer_reg_dat_sel && !wb_sel_i && ~wb_we_i;
68
69 assign wb_dat_o = (counter_timer_reg_cfg_sel) ? counter_timer_reg_cfg_do :
70 (counter_timer_reg_val_sel) ? counter_timer_reg_val_do :
71 counter_timer_reg_dat_do;
72 assign wb_ack_o = counter_timer_reg_cfg_sel || counter_timer_reg_val_sel ||
73 counter_timer_reg_dat_sel;
74
75 counter_timer_low counter_timer_low_inst (
76 .resetn(resetn),
77 .clkin(wb_clk_i),
78 .reg_val_we(reg_val_we),
79 .reg_val_di(mem_wdata),
80 .reg_val_do(counter_timer_reg_val_do),
81 .reg_cfg_we(reg_cfg_we),
82 .reg_cfg_di(mem_wdata),
83 .reg_cfg_do(counter_timer_reg_cfg_do),
84 .reg_dat_we(reg_dat_we),
85 .reg_dat_di(mem_wdata),
86 .reg_dat_do(counter_timer_reg_dat_do),
87 .stop_in(stop_in),
88 .strobe(strobe),
89 .is_offset(is_offset),
90 .enable_in(enable_in),
91 .stop_out(stop_out),
92 .enable_out(enable_out),
93 .irq_out(irq)
94 );
95
96endmodule
97
98module counter_timer_low (
99 input resetn,
100 input clkin,
101
102 input [3:0] reg_val_we,
103 input [31:0] reg_val_di,
104 output [31:0] reg_val_do,
105
106 input reg_cfg_we,
107 input [31:0] reg_cfg_di,
108 output [31:0] reg_cfg_do,
109
110 input [3:0] reg_dat_we,
111 input [31:0] reg_dat_di,
112 output [31:0] reg_dat_do,
113
114 input stop_in,
115 input enable_in,
116 output strobe,
117 output enable_out,
118 output stop_out,
119 output is_offset,
120 output irq_out
121);
122
123reg [31:0] value_cur;
124reg [31:0] value_reset;
125reg irq_out;
126wire stop_in; // High 32 bits counter has stopped
127reg strobe; // Strobe to high 32 bits counter; occurs
128 // one cycle before actual timeout and
129 // irq signal.
130reg stop_out; // Stop condition flag
131
132wire [31:0] value_cur_plus; // Next value, on up-count
133wire [31:0] value_cur_minus; // Next value, on down-count
134wire is_offset;
Tim Edwards581068f2020-11-19 12:45:25 -0500135wire loc_enable;
Tim Edwards7be29a22020-10-25 21:50:19 -0400136
137reg enable; // Enable (start) the counter/timer
138reg lastenable; // Previous state of enable (catch rising/falling edge)
139reg oneshot; // Set oneshot (1) mode or continuous (0) mode
140reg updown; // Count up (1) or down (0)
141reg irq_ena; // Enable interrupt on timeout
142reg chain; // Chain to a secondary timer
143
144// Configuration register
145
146assign reg_cfg_do = {27'd0, irq_ena, chain, updown, oneshot, enable};
147
148always @(posedge clkin or negedge resetn) begin
149 if (resetn == 1'b0) begin
150 enable <= 1'b0;
151 oneshot <= 1'b0;
152 updown <= 1'b0;
153 chain <= 1'b0;
154 irq_ena <= 1'b0;
155 end else begin
156 if (reg_cfg_we) begin
157 enable <= reg_cfg_di[0];
158 oneshot <= reg_cfg_di[1];
159 updown <= reg_cfg_di[2];
160 chain <= reg_cfg_di[3];
161 irq_ena <= reg_cfg_di[4];
162 end
163 end
164end
165
166// Counter/timer reset value register
167
168assign reg_val_do = value_reset;
169
170always @(posedge clkin or negedge resetn) begin
171 if (resetn == 1'b0) begin
172 value_reset <= 32'd0;
173 end else begin
174 if (reg_val_we[3]) value_reset[31:24] <= reg_val_di[31:24];
175 if (reg_val_we[2]) value_reset[23:16] <= reg_val_di[23:16];
176 if (reg_val_we[1]) value_reset[15:8] <= reg_val_di[15:8];
177 if (reg_val_we[0]) value_reset[7:0] <= reg_val_di[7:0];
178 end
179end
180
181assign reg_dat_do = value_cur;
182
183// Counter/timer current value register and timer implementation
184
185assign value_cur_plus = value_cur + 1;
186assign value_cur_minus = value_cur - 1;
187
Tim Edwards7be29a22020-10-25 21:50:19 -0400188assign loc_enable = (chain == 1'b1) ? (enable && enable_in) : enable;
189assign enable_out = enable;
190
191// If counting up and the stop condition on the low 32 bits is zero,
192// then signal to the high word counter that the stop condition of the
193// high word must be adjusted by one, since it will roll over at the same
194// time and must be signaled early.
195
196assign is_offset = ((updown == 1'b1) && (value_reset == 0));
197
198// When acting as low 32-bit word of a 64-bit chained counter:
199// It sets the output strobe on the stop condition, one cycle early.
200// It stops on the stop condition if "stop_in" is high.
201
202always @(posedge clkin or negedge resetn) begin
203 if (resetn == 1'b0) begin
204 value_cur <= 32'd0;
205 strobe <= 1'b0;
206 stop_out <= 1'b0;
207 irq_out <= 1'b0;
208 lastenable <= 1'b0;
209 end else begin
210 lastenable <= loc_enable;
211
212 if (reg_dat_we != 4'b0000) begin
213 if (reg_dat_we[3] == 1'b1) value_cur[31:24] <= reg_dat_di[31:24];
214 if (reg_dat_we[2] == 1'b1) value_cur[23:16] <= reg_dat_di[23:16];
215 if (reg_dat_we[1] == 1'b1) value_cur[15:8] <= reg_dat_di[15:8];
216 if (reg_dat_we[0] == 1'b1) value_cur[7:0] <= reg_dat_di[7:0];
217
218 end else if (loc_enable == 1'b1) begin
219 /* IRQ signals one cycle after stop_out, if IRQ is enabled */
220 irq_out <= (irq_ena) ? stop_out : 1'b0;
221
222 if (updown == 1'b1) begin
223 if (lastenable == 1'b0) begin
224 value_cur <= 32'd0;
225 strobe <= 1'b0;
226 stop_out <= 1'b0;
227 end else if (chain == 1'b1) begin
228 // Rollover strobe (2 clock cycles advanced)
229 if (value_cur == -1) begin
230 strobe <= 1'b1;
231 end else begin
232 strobe <= 1'b0;
233 end
234
235 // Chained counter behavior
236 if ((stop_in == 1'b1) && (value_cur == value_reset)) begin
237 if (oneshot != 1'b1) begin
238 value_cur <= 32'd0;
239 stop_out <= 1'b0;
240 end else begin
241 stop_out <= 1'b1;
242 end
243 end else begin
244 if ((stop_in == 1'b1) && (value_cur_plus == value_reset)) begin
245 stop_out <= 1'b1;
246 end else begin
247 stop_out <= 1'b0;
248 end
249 value_cur <= value_cur_plus; // count up
250 end
251 end else begin
252
253 // Single 32-bit counter behavior
254 if (value_cur == value_reset) begin
255 if (oneshot != 1'b1) begin
256 value_cur <= 32'd0;
257 stop_out <= 1'b0;
258 end else begin
259 stop_out <= 1'b1;
260 end
261 end else begin
262 if (value_cur_plus == value_reset) begin
263 stop_out <= 1'b1;
264 end else begin
265 stop_out <= 1'b0;
266 end
267 value_cur <= value_cur_plus; // count up
268 end
269 end
270 end else begin
271 if (lastenable == 1'b0) begin
272 value_cur <= value_reset;
273 stop_out <= 1'b0;
274 strobe <= 1'b0;
275 end else if (chain == 1'b1) begin
276 // Rollover strobe (2 clock cycles advanced)
277 if (value_cur == 2) begin
278 strobe <= 1'b1;
279 end else begin
280 strobe <= 1'b0;
281 end
282
283 // Chained counter behavior
284 if ((stop_in == 1'b1) && (value_cur == 32'd0)) begin
285 if (oneshot != 1'b1) begin
286 value_cur <= value_reset;
287 stop_out <= 1'b0;
288 end else begin
289 stop_out <= 1'b1;
290 end
291 end else begin
292 if ((stop_in == 1'b1) && (value_cur_minus == 32'd0)) begin
293 stop_out <= 1'b1;
294 end else begin
295 stop_out <= 1'b0;
296 end
297 value_cur <= value_cur_minus; // count down
298 end
299 end else begin
300
301 // Single 32-bit counter behavior
302 if (value_cur == 32'd0) begin
303 if (oneshot != 1'b1) begin
304 value_cur <= value_reset;
305 stop_out <= 1'b0;
306 end else begin
307 stop_out <= 1'b1;
308 end
309 end else begin
310 if (value_cur_minus == 32'd0) begin
311 stop_out <= 1'b1;
312 end else begin
313 stop_out <= 1'b0;
314 end
315 value_cur <= value_cur_minus; // count down
316 end
317 end
318 end
319 end else begin
320 strobe <= 1'b0;
321 end
322 end
323end
324
325endmodule
Tim Edwards581068f2020-11-19 12:45:25 -0500326`default_nettype wire