pdm.v 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * pdm.v
  3. *
  4. * vim: ts=4 sw=4
  5. *
  6. * Pulse Density Modulation core (1st order with dither)
  7. *
  8. * Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
  9. * All rights reserved.
  10. *
  11. * BSD 3-clause, see LICENSE.bsd
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions are met:
  15. * * Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. * * Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in the
  19. * documentation and/or other materials provided with the distribution.
  20. * * Neither the name of the <organization> nor the
  21. * names of its contributors may be used to endorse or promote products
  22. * derived from this software without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  26. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  27. * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  28. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  29. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  30. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  31. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  32. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. `default_nettype none
  36. module pdm #(
  37. parameter integer WIDTH = 8,
  38. parameter DITHER = "NO",
  39. parameter PHY = "GENERIC"
  40. )(
  41. // PWM out
  42. output wire pdm,
  43. // Config
  44. input wire [WIDTH-1:0] cfg_val,
  45. input wire cfg_oe,
  46. // Clock / Reset
  47. input wire clk,
  48. input wire rst
  49. );
  50. // Signals
  51. wire [WIDTH:0] inc;
  52. reg [WIDTH:0] acc;
  53. reg dither;
  54. wire pdm_i;
  55. // Delta Sigma
  56. assign inc = { acc[WIDTH], cfg_val };
  57. always @(posedge clk)
  58. begin
  59. if (rst)
  60. acc <= 0;
  61. else
  62. acc <= acc + inc + dither;
  63. end
  64. assign pdm_i = acc[WIDTH];
  65. // Dither generator
  66. generate
  67. if (DITHER == "YES") begin
  68. // Dither using a simple LFSR
  69. wire [7:0] lfsr_out;
  70. pdm_lfsr #(
  71. .WIDTH(8),
  72. .POLY(8'h71)
  73. ) lfsr_I (
  74. .out(lfsr_out),
  75. .clk(clk),
  76. .rst(rst)
  77. );
  78. always @(posedge clk)
  79. dither <= lfsr_out[0] ^ lfsr_out[3];
  80. end else begin
  81. // No dither
  82. always @(*)
  83. dither = 1'b0;
  84. end
  85. endgenerate
  86. // PHY (Basically just IO register)
  87. generate
  88. if (PHY == "NONE") begin
  89. // No PHY (and no OE support)
  90. assign pdm = pdm_i;
  91. end else if (PHY == "GENERIC") begin
  92. // Generic IO register, let tool figure it out
  93. reg pdm_d_r;
  94. reg pdm_oe_r;
  95. always @(posedge clk)
  96. begin
  97. pdm_d_r <= pdm_i;
  98. pdm_oe_r <= cfg_oe;
  99. end
  100. assign pdm = pdm_oe_r ? pdm_d_r : 1'bz;
  101. end else if (PHY == "ICE40") begin
  102. // iCE40 specific IOB
  103. SB_IO #(
  104. .PIN_TYPE(6'b110100),
  105. .PULLUP(1'b0),
  106. .NEG_TRIGGER(1'b0),
  107. .IO_STANDARD("SB_LVCMOS")
  108. ) io_reg_I (
  109. .PACKAGE_PIN(pdm),
  110. .LATCH_INPUT_VALUE(1'b0),
  111. .CLOCK_ENABLE(1'b1),
  112. .INPUT_CLK(1'b0),
  113. .OUTPUT_CLK(clk),
  114. .OUTPUT_ENABLE(cfg_oe),
  115. .D_OUT_0(pdm_i),
  116. .D_OUT_1(1'b0),
  117. .D_IN_0(),
  118. .D_IN_1()
  119. );
  120. end
  121. endgenerate
  122. endmodule // pdm
  123. module pdm_lfsr #(
  124. parameter integer WIDTH = 8,
  125. parameter POLY = 8'h71
  126. )(
  127. output reg [WIDTH-1:0] out,
  128. input wire clk,
  129. input wire rst
  130. );
  131. // Signals
  132. wire fb;
  133. // Linear Feedback
  134. assign fb = ^(out & POLY);
  135. // Register
  136. always @(posedge clk)
  137. if (rst)
  138. out <= { {(WIDTH-1){1'b0}}, 1'b1 };
  139. else
  140. out <= { fb, out[WIDTH-1:1] };
  141. endmodule // pdm_lfsr