blob: ea946f00d91a16b15bbd78f5ae0d52458b4698e4 [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 high 32 bits of a 64-bit counter
20 * when chained with the other counter
21 */
22
23module counter_timer_high_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 input enable_in,
41 input stop_in,
42 input strobe,
43 input is_offset,
44 output stop_out,
45 output enable_out,
46 output irq
47);
48 wire [31:0] counter_timer_reg_cfg_do;
49 wire [31:0] counter_timer_reg_val_do;
50 wire [31:0] counter_timer_reg_dat_do;
51
52 wire resetn = ~wb_rst_i;
53 wire valid = wb_stb_i && wb_cyc_i;
54 wire counter_timer_reg_cfg_sel = valid && (wb_adr_i == (BASE_ADR | CONFIG));
55 wire counter_timer_reg_val_sel = valid && (wb_adr_i == (BASE_ADR | VALUE));
56 wire counter_timer_reg_dat_sel = valid && (wb_adr_i == (BASE_ADR | DATA));
57
58 wire reg_cfg_we = (counter_timer_reg_cfg_sel) ?
59 (wb_sel_i[0] & {wb_we_i}): 1'b0;
60 wire [3:0] reg_val_we = (counter_timer_reg_val_sel) ?
61 (wb_sel_i & {4{wb_we_i}}): 4'b0000;
62 wire [3:0] reg_dat_we = (counter_timer_reg_dat_sel) ?
63 (wb_sel_i & {4{wb_we_i}}): 4'b0000;
64
65 wire [31:0] mem_wdata = wb_dat_i;
66 wire reg_dat_re = counter_timer_reg_dat_sel && !wb_sel_i && ~wb_we_i;
67
68 assign wb_dat_o = (counter_timer_reg_cfg_sel) ? counter_timer_reg_cfg_do :
69 (counter_timer_reg_val_sel) ? counter_timer_reg_val_do :
70 counter_timer_reg_dat_do;
71 assign wb_ack_o = counter_timer_reg_cfg_sel || counter_timer_reg_val_sel ||
72 counter_timer_reg_dat_sel;
73
74 counter_timer_high counter_timer_high_inst (
75 .resetn(resetn),
76 .clkin(wb_clk_i),
77 .reg_val_we(reg_val_we),
78 .reg_val_di(mem_wdata),
79 .reg_val_do(counter_timer_reg_val_do),
80 .reg_cfg_we(reg_cfg_we),
81 .reg_cfg_di(mem_wdata),
82 .reg_cfg_do(counter_timer_reg_cfg_do),
83 .reg_dat_we(reg_dat_we),
84 .reg_dat_di(mem_wdata),
85 .reg_dat_do(counter_timer_reg_dat_do),
86 .enable_in(enable_in),
87 .stop_in(stop_in),
88 .is_offset(is_offset),
89 .stop_out(stop_out),
90 .strobe(strobe),
91 .enable_out(enable_out),
92 .irq_out(irq)
93 );
94
95endmodule
96
97module counter_timer_high (
98 input resetn,
99 input clkin,
100
101 input [3:0] reg_val_we,
102 input [31:0] reg_val_di,
103 output [31:0] reg_val_do,
104
105 input reg_cfg_we,
106 input [31:0] reg_cfg_di,
107 output [31:0] reg_cfg_do,
108
109 input [3:0] reg_dat_we,
110 input [31:0] reg_dat_di,
111 output [31:0] reg_dat_do,
112 input stop_in,
113 input enable_in,
114 input is_offset,
115 input strobe,
116 output stop_out,
117 output enable_out,
118 output irq_out
119);
120
121reg [31:0] value_cur;
122reg [31:0] value_reset;
123reg irq_out;
124wire enable_in; // Enable from chained counter
125wire strobe; // Count strobe from low word counter
126wire enable_out; // Enable to chained counter (sync)
127reg stop_out; // Stop signal to low word counter
128
129wire [31:0] value_cur_plus; // Next value, on up-count
130wire [31:0] value_cur_minus; // Next value, on down-count
131wire [31:0] value_check_plus; // Value to check for stop condition during up count
132wire loc_enable; // Local enable
133
134reg enable; // Enable (start) the counter/timer
135reg lastenable; // Previous state of enable (catch rising/falling edge)
136reg oneshot; // Set oneshot (1) mode or continuous (0) mode
137reg updown; // Count up (1) or down (0)
138reg irq_ena; // Enable interrupt on timeout
139reg chain; // Chain to a secondary timer
140
141// Configuration register
142
143assign reg_cfg_do = {27'd0, irq_ena, chain, updown, oneshot, enable};
144
145always @(posedge clkin or negedge resetn) begin
146 if (resetn == 1'b0) begin
147 enable <= 1'b0;
148 oneshot <= 1'b0;
149 updown <= 1'b0;
150 chain <= 1'b0;
151 irq_ena <= 1'b0;
152 end else begin
153 if (reg_cfg_we) begin
154 enable <= reg_cfg_di[0];
155 oneshot <= reg_cfg_di[1];
156 updown <= reg_cfg_di[2];
157 chain <= reg_cfg_di[3];
158 irq_ena <= reg_cfg_di[4];
159 end
160 end
161end
162
163// Counter/timer reset value register
164
165assign reg_val_do = value_reset;
166
167always @(posedge clkin or negedge resetn) begin
168 if (resetn == 1'b0) begin
169 value_reset <= 32'd0;
170 end else begin
171 if (reg_val_we[3]) value_reset[31:24] <= reg_val_di[31:24];
172 if (reg_val_we[2]) value_reset[23:16] <= reg_val_di[23:16];
173 if (reg_val_we[1]) value_reset[15:8] <= reg_val_di[15:8];
174 if (reg_val_we[0]) value_reset[7:0] <= reg_val_di[7:0];
175 end
176end
177
178assign reg_dat_do = value_cur;
179
180// Counter/timer current value register and timer implementation
181
182assign value_cur_plus = value_cur + 1;
183assign value_cur_minus = value_cur - 1;
184
185assign value_check_plus = (is_offset) ? value_cur_plus : value_cur;
186
187assign enable_out = enable;
188assign loc_enable = (chain == 1'b1) ? (enable && enable_in) : enable;
189
190// When acting as the high 32 bit word of a 64-bit chained counter:
191//
192// It counts when the low 32-bit counter strobes (strobe == 1).
193// It sets "stop_out" and stops on the stop condition.
194
195always @(posedge clkin or negedge resetn) begin
196 if (resetn == 1'b0) begin
197 value_cur <= 32'd0;
198 stop_out <= 1'b0;
199 irq_out <= 1'b0;
200 lastenable <= 1'b0;
201 end else begin
202 lastenable <= loc_enable;
203
204 if (reg_dat_we != 4'b0000) begin
205 if (reg_dat_we[3] == 1'b1) value_cur[31:24] <= reg_dat_di[31:24];
206 if (reg_dat_we[2] == 1'b1) value_cur[23:16] <= reg_dat_di[23:16];
207 if (reg_dat_we[1] == 1'b1) value_cur[15:8] <= reg_dat_di[15:8];
208 if (reg_dat_we[0] == 1'b1) value_cur[7:0] <= reg_dat_di[7:0];
209
210 end else if (loc_enable == 1'b1) begin
211 /* IRQ signals one cycle after stop, if IRQ is enabled */
212 irq_out <= (irq_ena) ? stop_out : 1'b0;
213
214 if (updown == 1'b1) begin
215 if (lastenable == 1'b0) begin
216 value_cur <= 32'd0;
217 stop_out <= 1'b0;
218 end else if (chain) begin
219 // Chained counter behavior
220 if (value_check_plus == value_reset) begin
221 stop_out <= 1'b1;
222 end
223 if (stop_in == 1'b1) begin // lower word counter stopped
224 if (oneshot != 1'b1) begin
225 value_cur <= 32'd0; // reset count
226 stop_out <= 1'b0; // no longer stopped
227 end else if (strobe == 1'b1) begin
228 value_cur <= value_cur_plus;
229 end
230 end else if (strobe == 1'b1) begin
231 value_cur <= value_cur_plus;
232 end
233 end else begin
234 // Standalone counter behavior
235 if (value_cur == value_reset) begin
236 if (oneshot != 1'b1) begin
237 value_cur <= 32'd0;
238 stop_out <= 1'b0;
239 end else begin
240 stop_out <= 1'b1;
241 end
242 end else begin
243 if (value_cur_plus == 32'd0) begin
244 stop_out <= 1'b1;
245 end else begin
246 stop_out <= 1'b0;
247 end
248 value_cur <= value_cur_plus; // count up
249 end
250 end
251 end else begin
252 if (lastenable == 1'b0) begin
253 value_cur <= value_reset;
254 stop_out <= 1'b0;
255 end else if (chain) begin
256 // Chained counter behavior
257 if (value_cur == 32'd0) begin
258 stop_out <= 1'b1;
259 end
260 if (stop_in == 1'b1) begin // lower word counter stopped
261 if (oneshot != 1'b1) begin
262 value_cur <= value_reset; // reset count
263 stop_out <= 1'b0; // no longer stopped
264 end
265 end else if (strobe == 1'b1) begin
266 value_cur <= value_cur_minus; // count down
267 end
268 end else begin
269 // Standalone counter behavior
270 if (value_cur == 32'd0) begin
271 if (oneshot != 1'b1) begin
272 value_cur <= value_reset;
273 stop_out <= 1'b0;
274 end else begin
275 stop_out <= 1'b1;
276 end
277 end else begin
278 if (value_cur_minus == 32'd0) begin
279 stop_out <= 1'b1;
280 end else begin
281 stop_out <= 1'b0;
282 end
283 value_cur <= value_cur_minus; // count down
284 end
285 end
286 end
287 end else begin
288 stop_out <= 1'b0;
289 end
290 end
291end
292
293endmodule
Tim Edwards581068f2020-11-19 12:45:25 -0500294`default_nettype wire