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