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