blob: 2f1ea586d00a426b4fbb9ca3cda9682440cf1ec3 [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 high 32 bits of a 64-bit counter
5 * when chained with the other counter
6 */
7
8module counter_timer_high_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 input enable_in,
26 input stop_in,
27 input strobe,
28 input 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_high counter_timer_high_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 .enable_in(enable_in),
72 .stop_in(stop_in),
73 .is_offset(is_offset),
74 .stop_out(stop_out),
75 .strobe(strobe),
76 .enable_out(enable_out),
77 .irq_out(irq)
78 );
79
80endmodule
81
82module counter_timer_high (
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 input stop_in,
98 input enable_in,
99 input is_offset,
100 input strobe,
101 output stop_out,
102 output enable_out,
103 output irq_out
104);
105
106reg [31:0] value_cur;
107reg [31:0] value_reset;
108reg irq_out;
109wire enable_in; // Enable from chained counter
110wire strobe; // Count strobe from low word counter
111wire enable_out; // Enable to chained counter (sync)
112reg stop_out; // Stop signal to low word counter
113
114wire [31:0] value_cur_plus; // Next value, on up-count
115wire [31:0] value_cur_minus; // Next value, on down-count
116wire [31:0] value_check_plus; // Value to check for stop condition during up count
117wire loc_enable; // Local enable
118
119reg enable; // Enable (start) the counter/timer
120reg lastenable; // Previous state of enable (catch rising/falling edge)
121reg oneshot; // Set oneshot (1) mode or continuous (0) mode
122reg updown; // Count up (1) or down (0)
123reg irq_ena; // Enable interrupt on timeout
124reg chain; // Chain to a secondary timer
125
126// Configuration register
127
128assign reg_cfg_do = {27'd0, irq_ena, chain, updown, oneshot, enable};
129
130always @(posedge clkin or negedge resetn) begin
131 if (resetn == 1'b0) begin
132 enable <= 1'b0;
133 oneshot <= 1'b0;
134 updown <= 1'b0;
135 chain <= 1'b0;
136 irq_ena <= 1'b0;
137 end else begin
138 if (reg_cfg_we) begin
139 enable <= reg_cfg_di[0];
140 oneshot <= reg_cfg_di[1];
141 updown <= reg_cfg_di[2];
142 chain <= reg_cfg_di[3];
143 irq_ena <= reg_cfg_di[4];
144 end
145 end
146end
147
148// Counter/timer reset value register
149
150assign reg_val_do = value_reset;
151
152always @(posedge clkin or negedge resetn) begin
153 if (resetn == 1'b0) begin
154 value_reset <= 32'd0;
155 end else begin
156 if (reg_val_we[3]) value_reset[31:24] <= reg_val_di[31:24];
157 if (reg_val_we[2]) value_reset[23:16] <= reg_val_di[23:16];
158 if (reg_val_we[1]) value_reset[15:8] <= reg_val_di[15:8];
159 if (reg_val_we[0]) value_reset[7:0] <= reg_val_di[7:0];
160 end
161end
162
163assign reg_dat_do = value_cur;
164
165// Counter/timer current value register and timer implementation
166
167assign value_cur_plus = value_cur + 1;
168assign value_cur_minus = value_cur - 1;
169
170assign value_check_plus = (is_offset) ? value_cur_plus : value_cur;
171
172assign enable_out = enable;
173assign loc_enable = (chain == 1'b1) ? (enable && enable_in) : enable;
174
175// When acting as the high 32 bit word of a 64-bit chained counter:
176//
177// It counts when the low 32-bit counter strobes (strobe == 1).
178// It sets "stop_out" and stops on the stop condition.
179
180always @(posedge clkin or negedge resetn) begin
181 if (resetn == 1'b0) begin
182 value_cur <= 32'd0;
183 stop_out <= 1'b0;
184 irq_out <= 1'b0;
185 lastenable <= 1'b0;
186 end else begin
187 lastenable <= loc_enable;
188
189 if (reg_dat_we != 4'b0000) begin
190 if (reg_dat_we[3] == 1'b1) value_cur[31:24] <= reg_dat_di[31:24];
191 if (reg_dat_we[2] == 1'b1) value_cur[23:16] <= reg_dat_di[23:16];
192 if (reg_dat_we[1] == 1'b1) value_cur[15:8] <= reg_dat_di[15:8];
193 if (reg_dat_we[0] == 1'b1) value_cur[7:0] <= reg_dat_di[7:0];
194
195 end else if (loc_enable == 1'b1) begin
196 /* IRQ signals one cycle after stop, if IRQ is enabled */
197 irq_out <= (irq_ena) ? stop_out : 1'b0;
198
199 if (updown == 1'b1) begin
200 if (lastenable == 1'b0) begin
201 value_cur <= 32'd0;
202 stop_out <= 1'b0;
203 end else if (chain) begin
204 // Chained counter behavior
205 if (value_check_plus == value_reset) begin
206 stop_out <= 1'b1;
207 end
208 if (stop_in == 1'b1) begin // lower word counter stopped
209 if (oneshot != 1'b1) begin
210 value_cur <= 32'd0; // reset count
211 stop_out <= 1'b0; // no longer stopped
212 end else if (strobe == 1'b1) begin
213 value_cur <= value_cur_plus;
214 end
215 end else if (strobe == 1'b1) begin
216 value_cur <= value_cur_plus;
217 end
218 end else begin
219 // Standalone counter behavior
220 if (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 (value_cur_plus == 32'd0) 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
236 end else begin
237 if (lastenable == 1'b0) begin
238 value_cur <= value_reset;
239 stop_out <= 1'b0;
240 end else if (chain) begin
241 // Chained counter behavior
242 if (value_cur == 32'd0) begin
243 stop_out <= 1'b1;
244 end
245 if (stop_in == 1'b1) begin // lower word counter stopped
246 if (oneshot != 1'b1) begin
247 value_cur <= value_reset; // reset count
248 stop_out <= 1'b0; // no longer stopped
249 end
250 end else if (strobe == 1'b1) begin
251 value_cur <= value_cur_minus; // count down
252 end
253 end else begin
254 // Standalone counter behavior
255 if (value_cur == 32'd0) begin
256 if (oneshot != 1'b1) begin
257 value_cur <= value_reset;
258 stop_out <= 1'b0;
259 end else begin
260 stop_out <= 1'b1;
261 end
262 end else begin
263 if (value_cur_minus == 32'd0) begin
264 stop_out <= 1'b1;
265 end else begin
266 stop_out <= 1'b0;
267 end
268 value_cur <= value_cur_minus; // count down
269 end
270 end
271 end
272 end else begin
273 stop_out <= 1'b0;
274 end
275 end
276end
277
278endmodule
Tim Edwards581068f2020-11-19 12:45:25 -0500279`default_nettype wire