blob: 9e252819129431e2882184af16c186fda1866dbd [file] [log] [blame]
Tim Edwards04ba17f2020-10-02 22:27:50 -04001/* Simple 32-bit counter-timer for Caravel. */
2
3module counter_timer_wb # (
Tim Edwards856b0922020-10-09 16:30:22 -04004 parameter BASE_ADR = 32'h2400_0000,
Tim Edwards04ba17f2020-10-02 22:27:50 -04005 parameter CONFIG = 8'h00,
6 parameter VALUE = 8'h04,
7 parameter DATA = 8'h08
8) (
9 input wb_clk_i,
10 input wb_rst_i,
11 input [31:0] wb_adr_i,
12 input [31:0] wb_dat_i,
13 input [3:0] wb_sel_i,
14 input wb_we_i,
15 input wb_cyc_i,
16 input wb_stb_i,
17
18 output wb_ack_o,
19 output [31:0] wb_dat_o,
20 output irq
21);
22 wire [31:0] counter_timer_reg_cfg_do;
23 wire [31:0] counter_timer_reg_val_do;
24 wire [31:0] counter_timer_reg_dat_do;
25
26 wire resetn = ~wb_rst_i;
27 wire valid = wb_stb_i && wb_cyc_i;
28 wire counter_timer_reg_cfg_sel = valid && (wb_adr_i == (BASE_ADR | CONFIG));
29 wire counter_timer_reg_val_sel = valid && (wb_adr_i == (BASE_ADR | VALUE));
30 wire counter_timer_reg_dat_sel = valid && (wb_adr_i == (BASE_ADR | DATA));
31
32 wire reg_cfg_we = (counter_timer_reg_cfg_sel) ?
33 (wb_sel_i[0] & {wb_we_i}): 1'b0;
34 wire [3:0] reg_val_we = (counter_timer_reg_val_sel) ?
35 (wb_sel_i & {4{wb_we_i}}): 4'b0000;
36 wire [3:0] reg_dat_we = (counter_timer_reg_dat_sel) ?
37 (wb_sel_i & {4{wb_we_i}}): 4'b0000;
38
39 wire [31:0] mem_wdata = wb_dat_i;
40 wire reg_dat_re = counter_timer_reg_dat_sel && !wb_sel_i && ~wb_we_i;
41
42 assign wb_dat_o = (counter_timer_reg_cfg_sel) ? counter_timer_reg_cfg_do :
43 (counter_timer_reg_val_sel) ? counter_timer_reg_val_do :
44 counter_timer_reg_dat_do;
45 assign wb_ack_o = counter_timer_reg_cfg_sel || counter_timer_reg_val_sel ||
46 counter_timer_reg_dat_sel;
47
48 counter_timer counter_timer_inst (
49 .resetn(resetn),
50 .clkin(wb_clk_i),
51 .reg_val_we(reg_val_we),
52 .reg_val_di(mem_wdata),
53 .reg_val_do(counter_timer_reg_val_do),
54 .reg_cfg_we(reg_cfg_we),
55 .reg_cfg_di(mem_wdata),
56 .reg_cfg_do(counter_timer_reg_cfg_do),
57 .reg_dat_we(reg_dat_we),
58 .reg_dat_di(mem_wdata),
59 .reg_dat_do(counter_timer_reg_dat_do),
60 .irq_out(irq)
61 );
62
63endmodule
64
65module counter_timer (
66 input resetn,
67 input clkin,
68
69 input [3:0] reg_val_we,
70 input [31:0] reg_val_di,
71 output [31:0] reg_val_do,
72
73 input reg_cfg_we,
74 input [31:0] reg_cfg_di,
75 output [31:0] reg_cfg_do,
76
77 input [3:0] reg_dat_we,
78 input [31:0] reg_dat_di,
79 output [31:0] reg_dat_do,
80 output irq_out
81);
82
83reg [31:0] value_cur;
84reg [31:0] value_reset;
85reg irq_out;
86
87reg enable; // Enable (start) the counter/timer
Tim Edwards856b0922020-10-09 16:30:22 -040088reg lastenable; // Previous state of enable (catch rising/falling edge)
Tim Edwards04ba17f2020-10-02 22:27:50 -040089reg oneshot; // Set oneshot (1) mode or continuous (0) mode
90reg updown; // Count up (1) or down (0)
91reg irq_ena; // Enable interrupt on timeout
92
93// Configuration register
94
95assign reg_cfg_do = {28'd0, irq_ena, updown, oneshot, enable};
96
97always @(posedge clkin or negedge resetn) begin
98 if (resetn == 1'b0) begin
99 enable <= 1'b0;
Tim Edwards856b0922020-10-09 16:30:22 -0400100 lastenable <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400101 oneshot <= 1'b0;
102 updown <= 1'b0;
103 irq_ena <= 1'b0;
104 end else begin
Tim Edwards856b0922020-10-09 16:30:22 -0400105 lastenable <= enable;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400106 if (reg_cfg_we) begin
107 enable <= reg_cfg_di[0];
108 oneshot <= reg_cfg_di[1];
109 updown <= reg_cfg_di[2];
110 irq_ena <= reg_cfg_di[3];
111 end
112 end
113end
114
115// Counter/timer reset value register
116
117assign reg_val_do = value_reset;
118
119always @(posedge clkin or negedge resetn) begin
120 if (resetn == 1'b0) begin
121 value_reset <= 32'd0;
122 end else begin
Tim Edwards856b0922020-10-09 16:30:22 -0400123 if (reg_val_we[3]) value_reset[31:24] <= reg_val_di[31:24];
124 if (reg_val_we[2]) value_reset[23:16] <= reg_val_di[23:16];
125 if (reg_val_we[1]) value_reset[15:8] <= reg_val_di[15:8];
126 if (reg_val_we[0]) value_reset[7:0] <= reg_val_di[7:0];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400127 end
128end
129
130assign reg_dat_do = value_cur;
131
132// Counter/timer current value register and timer implementation
133
134always @(posedge clkin or negedge resetn) begin
135 if (resetn == 1'b0) begin
136 value_cur <= 32'd0;
137 irq_out <= 1'b0;
138 end else begin
139 if (reg_dat_we != 4'b0000) begin
140 if (reg_dat_we[3] == 1'b1) value_cur[31:24] <= reg_dat_di[31:24];
141 if (reg_dat_we[2] == 1'b1) value_cur[23:16] <= reg_dat_di[23:16];
142 if (reg_dat_we[1] == 1'b1) value_cur[15:8] <= reg_dat_di[15:8];
143 if (reg_dat_we[0] == 1'b1) value_cur[7:0] <= reg_dat_di[7:0];
144 end else if (enable == 1'b1) begin
145 if (updown == 1'b1) begin
Tim Edwards856b0922020-10-09 16:30:22 -0400146 if (lastenable == 1'b0) begin
147 value_cur <= 32'd0;
148 end else if (value_cur == value_reset) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400149 if (oneshot != 1'b1) begin
150 value_cur <= 32'd0;
151 end
152 irq_out <= irq_ena;
153 end else begin
154 value_cur <= value_cur + 1; // count up
155 irq_out <= 1'b0;
156 end
157 end else begin
Tim Edwards856b0922020-10-09 16:30:22 -0400158 if (lastenable == 1'b0) begin
159 value_cur <= value_reset;
160 end else if (value_cur == 32'd0) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400161 if (oneshot != 1'b1) begin
162 value_cur <= value_reset;
163 end
164 irq_out <= irq_ena;
165 end else begin
166 value_cur <= value_cur - 1; // count down
167 irq_out <= 1'b0;
168 end
169 end
170 end else begin
171 irq_out <= 1'b0;
172 end
173 end
174end
175
176endmodule