blob: ccd1431a6a8eede79cca8a193f0b9101d495063d [file] [log] [blame]
Tim Edwards04ba17f2020-10-02 22:27:50 -04001/* Simple 32-bit counter-timer for Caravel. */
2
3module counter_timer_wb # (
4 parameter BASE_ADR = 32'h2200_0000,
5 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
88reg oneshot; // Set oneshot (1) mode or continuous (0) mode
89reg updown; // Count up (1) or down (0)
90reg irq_ena; // Enable interrupt on timeout
91
92// Configuration register
93
94assign reg_cfg_do = {28'd0, irq_ena, updown, oneshot, enable};
95
96always @(posedge clkin or negedge resetn) begin
97 if (resetn == 1'b0) begin
98 enable <= 1'b0;
99 oneshot <= 1'b0;
100 updown <= 1'b0;
101 irq_ena <= 1'b0;
102 end else begin
103 if (reg_cfg_we) begin
104 enable <= reg_cfg_di[0];
105 oneshot <= reg_cfg_di[1];
106 updown <= reg_cfg_di[2];
107 irq_ena <= reg_cfg_di[3];
108 end
109 end
110end
111
112// Counter/timer reset value register
113
114assign reg_val_do = value_reset;
115
116always @(posedge clkin or negedge resetn) begin
117 if (resetn == 1'b0) begin
118 value_reset <= 32'd0;
119 end else begin
120 if (reg_val_we[3]) value_reset <= reg_val_di[31:24];
121 if (reg_val_we[2]) value_reset <= reg_val_di[23:16];
122 if (reg_val_we[1]) value_reset <= reg_val_di[15:8];
123 if (reg_val_we[0]) value_reset <= reg_val_di[7:0];
124 end
125end
126
127assign reg_dat_do = value_cur;
128
129// Counter/timer current value register and timer implementation
130
131always @(posedge clkin or negedge resetn) begin
132 if (resetn == 1'b0) begin
133 value_cur <= 32'd0;
134 irq_out <= 1'b0;
135 end else begin
136 if (reg_dat_we != 4'b0000) begin
137 if (reg_dat_we[3] == 1'b1) value_cur[31:24] <= reg_dat_di[31:24];
138 if (reg_dat_we[2] == 1'b1) value_cur[23:16] <= reg_dat_di[23:16];
139 if (reg_dat_we[1] == 1'b1) value_cur[15:8] <= reg_dat_di[15:8];
140 if (reg_dat_we[0] == 1'b1) value_cur[7:0] <= reg_dat_di[7:0];
141 end else if (enable == 1'b1) begin
142 if (updown == 1'b1) begin
143 if (value_cur == value_reset) begin
144 if (oneshot != 1'b1) begin
145 value_cur <= 32'd0;
146 end
147 irq_out <= irq_ena;
148 end else begin
149 value_cur <= value_cur + 1; // count up
150 irq_out <= 1'b0;
151 end
152 end else begin
153 if (value_cur == 32'd0) begin
154 if (oneshot != 1'b1) begin
155 value_cur <= value_reset;
156 end
157 irq_out <= irq_ena;
158 end else begin
159 value_cur <= value_cur - 1; // count down
160 irq_out <= 1'b0;
161 end
162 end
163 end else begin
164 irq_out <= 1'b0;
165 end
166 end
167end
168
169endmodule