blob: f5691824feb4594314d736413f7b695d95c077bf [file] [log] [blame]
Tim Edwardsb5d5b272020-10-02 22:27:50 -04001/* Simple 32-bit counter-timer for Caravel. */
2
3module counter_timer_wb # (
Tim Edwardsc47465c2020-10-09 16:30:22 -04004 parameter BASE_ADR = 32'h2400_0000,
Tim Edwardsb5d5b272020-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,
Tim Edwards4814a402020-10-19 19:43:52 -040011 input strobe_in,
Tim Edwardsb5d5b272020-10-02 22:27:50 -040012 input [31:0] wb_adr_i,
13 input [31:0] wb_dat_i,
14 input [3:0] wb_sel_i,
15 input wb_we_i,
16 input wb_cyc_i,
17 input wb_stb_i,
18
19 output wb_ack_o,
20 output [31:0] wb_dat_o,
Tim Edwards4814a402020-10-19 19:43:52 -040021 output strobe_out,
Tim Edwardsb5d5b272020-10-02 22:27:50 -040022 output irq
23);
24 wire [31:0] counter_timer_reg_cfg_do;
25 wire [31:0] counter_timer_reg_val_do;
26 wire [31:0] counter_timer_reg_dat_do;
27
28 wire resetn = ~wb_rst_i;
29 wire valid = wb_stb_i && wb_cyc_i;
30 wire counter_timer_reg_cfg_sel = valid && (wb_adr_i == (BASE_ADR | CONFIG));
31 wire counter_timer_reg_val_sel = valid && (wb_adr_i == (BASE_ADR | VALUE));
32 wire counter_timer_reg_dat_sel = valid && (wb_adr_i == (BASE_ADR | DATA));
33
34 wire reg_cfg_we = (counter_timer_reg_cfg_sel) ?
35 (wb_sel_i[0] & {wb_we_i}): 1'b0;
36 wire [3:0] reg_val_we = (counter_timer_reg_val_sel) ?
37 (wb_sel_i & {4{wb_we_i}}): 4'b0000;
38 wire [3:0] reg_dat_we = (counter_timer_reg_dat_sel) ?
39 (wb_sel_i & {4{wb_we_i}}): 4'b0000;
40
41 wire [31:0] mem_wdata = wb_dat_i;
42 wire reg_dat_re = counter_timer_reg_dat_sel && !wb_sel_i && ~wb_we_i;
43
44 assign wb_dat_o = (counter_timer_reg_cfg_sel) ? counter_timer_reg_cfg_do :
45 (counter_timer_reg_val_sel) ? counter_timer_reg_val_do :
46 counter_timer_reg_dat_do;
47 assign wb_ack_o = counter_timer_reg_cfg_sel || counter_timer_reg_val_sel ||
48 counter_timer_reg_dat_sel;
49
50 counter_timer counter_timer_inst (
51 .resetn(resetn),
52 .clkin(wb_clk_i),
Tim Edwards4814a402020-10-19 19:43:52 -040053 .strobe_in(strobe_in),
Tim Edwardsb5d5b272020-10-02 22:27:50 -040054 .reg_val_we(reg_val_we),
55 .reg_val_di(mem_wdata),
56 .reg_val_do(counter_timer_reg_val_do),
57 .reg_cfg_we(reg_cfg_we),
58 .reg_cfg_di(mem_wdata),
59 .reg_cfg_do(counter_timer_reg_cfg_do),
60 .reg_dat_we(reg_dat_we),
61 .reg_dat_di(mem_wdata),
62 .reg_dat_do(counter_timer_reg_dat_do),
Tim Edwards4814a402020-10-19 19:43:52 -040063 .strobe_out(strobe_out),
Tim Edwardsb5d5b272020-10-02 22:27:50 -040064 .irq_out(irq)
65 );
66
67endmodule
68
69module counter_timer (
70 input resetn,
71 input clkin,
Tim Edwards4814a402020-10-19 19:43:52 -040072 input strobe_in,
Tim Edwardsb5d5b272020-10-02 22:27:50 -040073
74 input [3:0] reg_val_we,
75 input [31:0] reg_val_di,
76 output [31:0] reg_val_do,
77
78 input reg_cfg_we,
79 input [31:0] reg_cfg_di,
80 output [31:0] reg_cfg_do,
81
82 input [3:0] reg_dat_we,
83 input [31:0] reg_dat_di,
84 output [31:0] reg_dat_do,
Tim Edwards4814a402020-10-19 19:43:52 -040085 output strobe_out,
Tim Edwardsb5d5b272020-10-02 22:27:50 -040086 output irq_out
87);
88
89reg [31:0] value_cur;
90reg [31:0] value_reset;
Tim Edwards4814a402020-10-19 19:43:52 -040091reg strobe_out;
92wire irq_out;
Tim Edwardsb5d5b272020-10-02 22:27:50 -040093
94reg enable; // Enable (start) the counter/timer
Tim Edwardsc47465c2020-10-09 16:30:22 -040095reg lastenable; // Previous state of enable (catch rising/falling edge)
Tim Edwardsb5d5b272020-10-02 22:27:50 -040096reg oneshot; // Set oneshot (1) mode or continuous (0) mode
97reg updown; // Count up (1) or down (0)
98reg irq_ena; // Enable interrupt on timeout
Tim Edwards4814a402020-10-19 19:43:52 -040099reg chain; // Chain to a secondary timer
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400100
101// Configuration register
102
Tim Edwards4814a402020-10-19 19:43:52 -0400103assign reg_cfg_do = {27'd0, irq_ena, chain, updown, oneshot, enable};
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400104
105always @(posedge clkin or negedge resetn) begin
106 if (resetn == 1'b0) begin
107 enable <= 1'b0;
Tim Edwardsc47465c2020-10-09 16:30:22 -0400108 lastenable <= 1'b0;
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400109 oneshot <= 1'b0;
110 updown <= 1'b0;
Tim Edwards4814a402020-10-19 19:43:52 -0400111 chain <= 1'b0;
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400112 irq_ena <= 1'b0;
113 end else begin
Tim Edwardsc47465c2020-10-09 16:30:22 -0400114 lastenable <= enable;
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400115 if (reg_cfg_we) begin
116 enable <= reg_cfg_di[0];
117 oneshot <= reg_cfg_di[1];
118 updown <= reg_cfg_di[2];
Tim Edwards4814a402020-10-19 19:43:52 -0400119 chain <= reg_cfg_di[3];
120 irq_ena <= reg_cfg_di[4];
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400121 end
122 end
123end
124
125// Counter/timer reset value register
126
127assign reg_val_do = value_reset;
128
129always @(posedge clkin or negedge resetn) begin
130 if (resetn == 1'b0) begin
131 value_reset <= 32'd0;
132 end else begin
Tim Edwardsc47465c2020-10-09 16:30:22 -0400133 if (reg_val_we[3]) value_reset[31:24] <= reg_val_di[31:24];
134 if (reg_val_we[2]) value_reset[23:16] <= reg_val_di[23:16];
135 if (reg_val_we[1]) value_reset[15:8] <= reg_val_di[15:8];
136 if (reg_val_we[0]) value_reset[7:0] <= reg_val_di[7:0];
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400137 end
138end
139
140assign reg_dat_do = value_cur;
141
142// Counter/timer current value register and timer implementation
143
Tim Edwards4814a402020-10-19 19:43:52 -0400144assign irq_out = (irq_ena) ? strobe_out : 1'b0;
145
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400146always @(posedge clkin or negedge resetn) begin
147 if (resetn == 1'b0) begin
148 value_cur <= 32'd0;
Tim Edwards4814a402020-10-19 19:43:52 -0400149 strobe_out <= 1'b0;
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400150 end else begin
151 if (reg_dat_we != 4'b0000) begin
152 if (reg_dat_we[3] == 1'b1) value_cur[31:24] <= reg_dat_di[31:24];
153 if (reg_dat_we[2] == 1'b1) value_cur[23:16] <= reg_dat_di[23:16];
154 if (reg_dat_we[1] == 1'b1) value_cur[15:8] <= reg_dat_di[15:8];
155 if (reg_dat_we[0] == 1'b1) value_cur[7:0] <= reg_dat_di[7:0];
156 end else if (enable == 1'b1) begin
157 if (updown == 1'b1) begin
Tim Edwardsc47465c2020-10-09 16:30:22 -0400158 if (lastenable == 1'b0) begin
159 value_cur <= 32'd0;
160 end else if (value_cur == value_reset) begin
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400161 if (oneshot != 1'b1) begin
162 value_cur <= 32'd0;
163 end
Tim Edwards4814a402020-10-19 19:43:52 -0400164 strobe_out <= 1'b1;
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400165 end else begin
Tim Edwards4814a402020-10-19 19:43:52 -0400166 if ((chain == 1'b0) || ((chain == 1'b1) && (strobe_in == 1'b1))) begin
167 value_cur <= value_cur + 1; // count up
168 strobe_out <= 1'b0;
169 end
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400170 end
171 end else begin
Tim Edwardsc47465c2020-10-09 16:30:22 -0400172 if (lastenable == 1'b0) begin
173 value_cur <= value_reset;
174 end else if (value_cur == 32'd0) begin
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400175 if (oneshot != 1'b1) begin
176 value_cur <= value_reset;
177 end
Tim Edwards4814a402020-10-19 19:43:52 -0400178 strobe_out <= 1'b1;
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400179 end else begin
Tim Edwards4814a402020-10-19 19:43:52 -0400180 if ((chain == 1'b0) || ((chain == 1'b1) && (strobe_in == 1'b1))) begin
181 value_cur <= value_cur - 1; // count down
182 strobe_out <= 1'b0;
183 end
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400184 end
185 end
186 end else begin
Tim Edwards4814a402020-10-19 19:43:52 -0400187 strobe_out <= 1'b0;
Tim Edwardsb5d5b272020-10-02 22:27:50 -0400188 end
189 end
190end
191
192endmodule