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