dfu_helper.v 3.1 KB

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