dfu_helper.v 2.8 KB

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