blob: fd94d2cb3f31c73478189936f4e5a58c8f1976b4 [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;
Tim Edwards581068f2020-11-19 12:45:25 -0500120wire loc_enable;
Tim Edwards7be29a22020-10-25 21:50:19 -0400121
122reg enable; // Enable (start) the counter/timer
123reg lastenable; // Previous state of enable (catch rising/falling edge)
124reg oneshot; // Set oneshot (1) mode or continuous (0) mode
125reg updown; // Count up (1) or down (0)
126reg irq_ena; // Enable interrupt on timeout
127reg chain; // Chain to a secondary timer
128
129// Configuration register
130
131assign reg_cfg_do = {27'd0, irq_ena, chain, updown, oneshot, enable};
132
133always @(posedge clkin or negedge resetn) begin
134 if (resetn == 1'b0) begin
135 enable <= 1'b0;
136 oneshot <= 1'b0;
137 updown <= 1'b0;
138 chain <= 1'b0;
139 irq_ena <= 1'b0;
140 end else begin
141 if (reg_cfg_we) begin
142 enable <= reg_cfg_di[0];
143 oneshot <= reg_cfg_di[1];
144 updown <= reg_cfg_di[2];
145 chain <= reg_cfg_di[3];
146 irq_ena <= reg_cfg_di[4];
147 end
148 end
149end
150
151// Counter/timer reset value register
152
153assign reg_val_do = value_reset;
154
155always @(posedge clkin or negedge resetn) begin
156 if (resetn == 1'b0) begin
157 value_reset <= 32'd0;
158 end else begin
159 if (reg_val_we[3]) value_reset[31:24] <= reg_val_di[31:24];
160 if (reg_val_we[2]) value_reset[23:16] <= reg_val_di[23:16];
161 if (reg_val_we[1]) value_reset[15:8] <= reg_val_di[15:8];
162 if (reg_val_we[0]) value_reset[7:0] <= reg_val_di[7:0];
163 end
164end
165
166assign reg_dat_do = value_cur;
167
168// Counter/timer current value register and timer implementation
169
170assign value_cur_plus = value_cur + 1;
171assign value_cur_minus = value_cur - 1;
172
Tim Edwards7be29a22020-10-25 21:50:19 -0400173assign loc_enable = (chain == 1'b1) ? (enable && enable_in) : enable;
174assign enable_out = enable;
175
176// If counting up and the stop condition on the low 32 bits is zero,
177// then signal to the high word counter that the stop condition of the
178// high word must be adjusted by one, since it will roll over at the same
179// time and must be signaled early.
180
181assign is_offset = ((updown == 1'b1) && (value_reset == 0));
182
183// When acting as low 32-bit word of a 64-bit chained counter:
184// It sets the output strobe on the stop condition, one cycle early.
185// It stops on the stop condition if "stop_in" is high.
186
187always @(posedge clkin or negedge resetn) begin
188 if (resetn == 1'b0) begin
189 value_cur <= 32'd0;
190 strobe <= 1'b0;
191 stop_out <= 1'b0;
192 irq_out <= 1'b0;
193 lastenable <= 1'b0;
194 end else begin
195 lastenable <= loc_enable;
196
197 if (reg_dat_we != 4'b0000) begin
198 if (reg_dat_we[3] == 1'b1) value_cur[31:24] <= reg_dat_di[31:24];
199 if (reg_dat_we[2] == 1'b1) value_cur[23:16] <= reg_dat_di[23:16];
200 if (reg_dat_we[1] == 1'b1) value_cur[15:8] <= reg_dat_di[15:8];
201 if (reg_dat_we[0] == 1'b1) value_cur[7:0] <= reg_dat_di[7:0];
202
203 end else if (loc_enable == 1'b1) begin
204 /* IRQ signals one cycle after stop_out, if IRQ is enabled */
205 irq_out <= (irq_ena) ? stop_out : 1'b0;
206
207 if (updown == 1'b1) begin
208 if (lastenable == 1'b0) begin
209 value_cur <= 32'd0;
210 strobe <= 1'b0;
211 stop_out <= 1'b0;
212 end else if (chain == 1'b1) begin
213 // Rollover strobe (2 clock cycles advanced)
214 if (value_cur == -1) begin
215 strobe <= 1'b1;
216 end else begin
217 strobe <= 1'b0;
218 end
219
220 // Chained counter behavior
221 if ((stop_in == 1'b1) && (value_cur == value_reset)) begin
222 if (oneshot != 1'b1) begin
223 value_cur <= 32'd0;
224 stop_out <= 1'b0;
225 end else begin
226 stop_out <= 1'b1;
227 end
228 end else begin
229 if ((stop_in == 1'b1) && (value_cur_plus == value_reset)) begin
230 stop_out <= 1'b1;
231 end else begin
232 stop_out <= 1'b0;
233 end
234 value_cur <= value_cur_plus; // count up
235 end
236 end else begin
237
238 // Single 32-bit counter behavior
239 if (value_cur == value_reset) begin
240 if (oneshot != 1'b1) begin
241 value_cur <= 32'd0;
242 stop_out <= 1'b0;
243 end else begin
244 stop_out <= 1'b1;
245 end
246 end else begin
247 if (value_cur_plus == value_reset) begin
248 stop_out <= 1'b1;
249 end else begin
250 stop_out <= 1'b0;
251 end
252 value_cur <= value_cur_plus; // count up
253 end
254 end
255 end else begin
256 if (lastenable == 1'b0) begin
257 value_cur <= value_reset;
258 stop_out <= 1'b0;
259 strobe <= 1'b0;
260 end else if (chain == 1'b1) begin
261 // Rollover strobe (2 clock cycles advanced)
262 if (value_cur == 2) begin
263 strobe <= 1'b1;
264 end else begin
265 strobe <= 1'b0;
266 end
267
268 // Chained counter behavior
269 if ((stop_in == 1'b1) && (value_cur == 32'd0)) begin
270 if (oneshot != 1'b1) begin
271 value_cur <= value_reset;
272 stop_out <= 1'b0;
273 end else begin
274 stop_out <= 1'b1;
275 end
276 end else begin
277 if ((stop_in == 1'b1) && (value_cur_minus == 32'd0)) begin
278 stop_out <= 1'b1;
279 end else begin
280 stop_out <= 1'b0;
281 end
282 value_cur <= value_cur_minus; // count down
283 end
284 end else begin
285
286 // Single 32-bit counter behavior
287 if (value_cur == 32'd0) begin
288 if (oneshot != 1'b1) begin
289 value_cur <= value_reset;
290 stop_out <= 1'b0;
291 end else begin
292 stop_out <= 1'b1;
293 end
294 end else begin
295 if (value_cur_minus == 32'd0) begin
296 stop_out <= 1'b1;
297 end else begin
298 stop_out <= 1'b0;
299 end
300 value_cur <= value_cur_minus; // count down
301 end
302 end
303 end
304 end else begin
305 strobe <= 1'b0;
306 end
307 end
308end
309
310endmodule
Tim Edwards581068f2020-11-19 12:45:25 -0500311`default_nettype wire