mc97_rfi.v 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * mc97_rfi.v
  3. *
  4. * Detects 10-100 Hz ringing foR ring indication
  5. *
  6. * vim: ts=4 sw=4
  7. *
  8. * Copyright (C) 2021 Sylvain Munaut <tnt@246tNt.com>
  9. * SPDX-License-Identifier: CERN-OHL-P-2.0
  10. */
  11. `default_nettype none
  12. module mc97_rfi #(
  13. parameter integer CLK_FREQ = 24_000_000,
  14. parameter integer F_MIN = 10, /* Hz */
  15. parameter integer F_MAX = 100 /* Hz */
  16. )(
  17. // PCM tap
  18. input wire [15:0] pcm_data,
  19. input wire pcm_stb,
  20. // Ring Frequency Indication
  21. output reg rfi,
  22. // Clock / Reset
  23. input wire clk,
  24. input wire rst
  25. );
  26. localparam integer CYC_MIN = CLK_FREQ / F_MAX;
  27. localparam integer CYC_MAX = CLK_FREQ / F_MIN;
  28. localparam integer WMIN = $clog2(CYC_MIN);
  29. localparam integer WMAX = $clog2(CYC_MAX);
  30. localparam [WMIN-1:0] K_MIN = CYC_MIN;
  31. localparam [WMAX-1:0] K_MAX = CYC_MAX;
  32. // Signals
  33. // -------
  34. // Rising edge detector
  35. wire rid_is_neg;
  36. wire rid_is_pos;
  37. reg [2:0] rid_cnt;
  38. wire rid_cnt_max;
  39. reg rid_armed;
  40. reg rid_stb;
  41. // Interval counter
  42. reg [WMIN:0] ic_min;
  43. reg [WMAX:0] ic_max;
  44. reg ic_max_msb_r;
  45. reg ic_armed;
  46. reg ic_stb_ok;
  47. reg ic_stb_err;
  48. // Validation
  49. reg [1:0] vs_cnt_err;
  50. reg [1:0] vs_cnt_ok;
  51. // Detect "Rising edges"
  52. // ---------------------
  53. // Anything going for < -16384 to >= 16384
  54. // in less than 8 samples
  55. assign rid_is_neg = (pcm_data[15:14] == 2'b10);
  56. assign rid_is_pos = (pcm_data[15:14] == 2'b01);
  57. always @(posedge clk or posedge rst)
  58. if (rst)
  59. rid_cnt <= 0;
  60. else if (pcm_stb)
  61. casez ({rid_is_neg, rid_cnt})
  62. 4'b1zzz: rid_cnt <= 3'b000;
  63. 4'b0000: rid_cnt <= 3'b001;
  64. 4'b0001: rid_cnt <= 3'b010;
  65. 4'b0010: rid_cnt <= 3'b011;
  66. 4'b0011: rid_cnt <= 3'b100;
  67. 4'b0100: rid_cnt <= 3'b101;
  68. 4'b0101: rid_cnt <= 3'b110;
  69. 4'b0110: rid_cnt <= 3'b111;
  70. 4'b0111: rid_cnt <= 3'b111;
  71. default: rid_cnt <= 3'bxxx;
  72. endcase
  73. assign rid_cnt_max = (rid_cnt == 3'b111);
  74. always @(posedge clk or posedge rst)
  75. if (rst)
  76. rid_armed <= 0;
  77. else if (pcm_stb)
  78. rid_armed <= (rid_armed | rid_is_neg) & ~(rid_cnt_max | rid_is_pos);
  79. always @(posedge clk)
  80. rid_stb <= rid_armed & rid_is_pos & ~rid_cnt_max & pcm_stb;
  81. // Interval counter
  82. // ----------------
  83. // Measure interval between rising edge and detects :
  84. // - underflow : Rising edge less than 10 ms appart
  85. // - overflow : No rising edge for more than 100 ms
  86. // - ok : Rising edge occured withing expected interval
  87. always @(posedge clk)
  88. if (rid_stb) begin
  89. ic_min <= { 1'b1, K_MIN };
  90. ic_max <= { 1'b1, K_MAX };
  91. end else begin
  92. ic_min <= ic_min - ic_min[WMIN];
  93. ic_max <= ic_max[WMAX] ? (ic_max - 1) : { 1'b1, K_MAX }; // Auto-repeat if no edge
  94. end
  95. always @(posedge clk)
  96. ic_max_msb_r <= ic_max[WMAX];
  97. always @(posedge clk)
  98. if (rst)
  99. ic_armed <= 1'b0;
  100. else
  101. ic_armed <= (ic_armed & ic_max[WMAX]) | rid_stb;
  102. always @(posedge clk)
  103. begin
  104. ic_stb_ok <= ic_armed & rid_stb & ~ic_min[WMIN] & ic_max[WMAX];
  105. ic_stb_err <= (ic_armed & rid_stb & ic_min[WMIN]) | (ic_max_msb_r & ~ic_max[WMAX]);
  106. end
  107. // Validation
  108. // ----------
  109. // Assert on 4 succesive valid
  110. // Deassert on 4 succesive invalid ones
  111. always @(posedge clk)
  112. if (rst)
  113. vs_cnt_err <= 0;
  114. else
  115. vs_cnt_err <= (vs_cnt_err + ic_stb_err) & {2{~ic_stb_ok}};
  116. always @(posedge clk)
  117. if (rst)
  118. vs_cnt_ok <= 0;
  119. else
  120. vs_cnt_ok <= (vs_cnt_ok + ic_stb_ok) & {2{~ic_stb_err}};
  121. always @(posedge clk)
  122. if (rst)
  123. rfi <= 0;
  124. else
  125. rfi <= (rfi & ~&vs_cnt_err) | &vs_cnt_ok;
  126. endmodule // mc97_rfi