blob: 0ef14f384c258829c5b1e5738a7513085654af08 [file] [log] [blame]
Sylvain Munaut21b03ba2020-09-14 10:01:45 +02001/*
2 * dfu_helper.v
3 *
4 * vim: ts=4 sw=4
5 *
6 * Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
7 * SPDX-License-Identifier: CERN-OHL-P-2.0
8 */
9
10`default_nettype none
11
12module dfu_helper #(
13 parameter integer TIMER_WIDTH = 24,
14 parameter integer BTN_MODE = 3, // [2] Use btn_tick, [1] Include IO buffer, [0] Invert (active-low)
15 parameter integer DFU_MODE = 0 // 0 = For user app, 1 = For bootloader
16)(
17 // External control
18 input wire [1:0] boot_sel,
19 input wire boot_now,
20
21 // Button
22 input wire btn_pad,
23 input wire btn_tick,
24
25 // Outputs
26 output wire btn_val,
27 output reg rst_req,
28
29 // Clock
30 input wire clk,
31 input wire rst
32);
33
34 // Signals
35 // -------
36
37 // Button
38 wire btn_iob;
39 wire btn_v;
40 wire btn_r;
41 wire btn_f;
42
43 // Timer and arming logic
44 reg armed;
45 reg [TIMER_WIDTH-1:0] timer;
46 (* keep="true" *) wire timer_act;
47
48 // Boot logic
49 reg [1:0] wb_sel;
50 reg wb_req;
51 reg wb_now;
52
53
54 // Button logic
55 // ------------
56
57 // IOB
58 generate
59 if (BTN_MODE[1])
60 SB_IO #(
61 .PIN_TYPE(6'b000000), // Reg input, no output
62 .PULLUP(1'b1),
63 .IO_STANDARD("SB_LVCMOS")
64 ) btn_iob_I (
65 .PACKAGE_PIN(btn_pad),
66 .INPUT_CLK (clk),
67 .D_IN_0 (btn_iob)
68 );
69 else
70 assign btn_iob = btn_pad;
71 endgenerate
72
73 // Deglitch
74 glitch_filter #(
75 .L(BTN_MODE[2] ? 2 : 4),
76 .RST_VAL(BTN_MODE[0]),
77 .WITH_SYNCHRONIZER(1),
78 .WITH_SAMP_COND(BTN_MODE[2])
79 ) btn_flt_I (
80 .in (btn_iob ^ BTN_MODE[0]),
81 .samp_cond(btn_tick),
82 .val (btn_v),
83 .rise (btn_r),
84 .fall (btn_f),
85 .clk (clk),
86`ifdef SIM
87 .rst (rst)
88`else
89 // Don't reset so we let the filter settle before
90 // the rest of the logic engages
91 .rst (1'b0)
92`endif
93 );
94
95 assign btn_val = btn_v;
96
97
98 // Arming & Timer
99 // --------------
100
101 assign timer_act = btn_v ^ armed;
102
103 always @(posedge clk or posedge rst)
104 if (rst)
105 armed <= 1'b0;
106 else
107 armed <= armed | timer[TIMER_WIDTH-2];
108
109 always @(posedge clk or posedge rst)
110 if (rst)
111 timer <= 0;
112 else
113 timer <= timer_act ? { TIMER_WIDTH{1'b0} } : (timer + { { (TIMER_WIDTH-1){1'b0} }, ~timer[TIMER_WIDTH-1] });
114
115
116 // Boot Logic
117 // ----------
118
119 // Decision
120 always @(posedge clk or posedge rst)
121 if (rst) begin
122 wb_sel <= 2'b00;
123 wb_req <= 1'b0;
124 rst_req <= 1'b0;
125 end else if (~wb_req) begin
126 if (boot_now) begin
127 // External boot request
128 wb_sel <= boot_sel;
129 wb_req <= 1'b1;
130 rst_req <= 1'b0;
131 end else begin
132 if (DFU_MODE == 1) begin
133 // We're in a DFU bootloader, any button press results in
134 // boot to application
135 wb_sel <= 2'b10;
136 wb_req <= wb_now | (armed & btn_f);
137 rst_req <= 1'b0;
138 end else begin
139 // We're in user application, short press resets the
140 // logic, long press triggers DFU reboot
141 wb_sel <= 2'b01;
142 wb_req <= wb_now | (armed & btn_f & timer[TIMER_WIDTH-1]);
143 rst_req <= rst_req | (armed & btn_f & ~timer[TIMER_WIDTH-1]);
144 end
145 end
146 end
147
148 // Ensure select bits are set before the boot pulse
149 always @(posedge clk or posedge rst)
150 if (rst)
151 wb_now <= 1'b0;
152 else
153 wb_now <= wb_req;
154
155 // IP core
156 SB_WARMBOOT warmboot (
157 .BOOT(wb_now),
158 .S0(wb_sel[0]),
159 .S1(wb_sel[1])
160 );
161
162endmodule // dfu_helper