IDivider.v 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * 32-bit multicycle signed or unsigned integer divider
  3. */
  4. module IDivider #(
  5. parameter DATA_WIDTH = 32
  6. ) (
  7. input clk,
  8. input rst,
  9. input [DATA_WIDTH-1:0] a,
  10. input [DATA_WIDTH-1:0] b,
  11. input signed_ope,
  12. input write_a,
  13. input start,
  14. input flush,
  15. output reg [DATA_WIDTH-1:0] quotient,
  16. output reg [DATA_WIDTH-1:0] remainder,
  17. output ready
  18. );
  19. reg start_prev = 0;
  20. reg [DATA_WIDTH-1:0] dividend = 0;
  21. reg [DATA_WIDTH-1:0] divisor = 0;
  22. localparam COUNT_WIDTH = $clog2(DATA_WIDTH + 1);
  23. reg r_ready = 0;
  24. reg r_signed_ope = 0;
  25. reg [COUNT_WIDTH-1:0] r_count = 0;
  26. reg [DATA_WIDTH-1:0] r_quotient = 0;
  27. wire w_dividend_sign;
  28. reg r_dividend_sign = 0;
  29. wire remainder_sign;
  30. reg [DATA_WIDTH:0] r_remainder = 0;
  31. reg [DATA_WIDTH-1:0] r_divisor = 0;
  32. wire [DATA_WIDTH:0] divisor_ext;
  33. wire divisor_sign;
  34. wire [DATA_WIDTH:0] rem_quo;
  35. wire diff_sign;
  36. wire [DATA_WIDTH:0] sub_add;
  37. assign ready = r_ready;
  38. assign divisor_sign = r_divisor[DATA_WIDTH-1] & r_signed_ope;
  39. assign divisor_ext = {divisor_sign, r_divisor};
  40. assign remainder_sign = r_remainder[DATA_WIDTH];
  41. assign rem_quo = {r_remainder[DATA_WIDTH-1:0], r_quotient[DATA_WIDTH-1]};
  42. assign diff_sign = remainder_sign ^ divisor_sign;
  43. assign sub_add = diff_sign ? rem_quo + divisor_ext :
  44. rem_quo - divisor_ext;
  45. // after process
  46. always @(*) begin
  47. quotient = (r_quotient << 1) | 1;
  48. remainder = r_remainder[DATA_WIDTH-1:0];
  49. if (r_remainder == 0) begin
  50. // do nothing
  51. end else if (r_remainder == divisor_ext) begin
  52. quotient = quotient + 1;
  53. remainder = remainder - r_divisor;
  54. end else if (r_remainder == -divisor_ext) begin
  55. quotient = quotient - 1;
  56. remainder = remainder + r_divisor;
  57. end else if (remainder_sign ^ r_dividend_sign) begin
  58. if (diff_sign) begin
  59. quotient = quotient - 1;
  60. remainder = remainder + r_divisor;
  61. end else begin
  62. quotient = quotient + 1;
  63. remainder = remainder - r_divisor;
  64. end
  65. end
  66. end
  67. assign w_dividend_sign = dividend[DATA_WIDTH-1] & signed_ope;
  68. always @(posedge clk)
  69. begin
  70. start_prev <= start;
  71. if (write_a)
  72. begin
  73. dividend <= a;
  74. end
  75. if (start && !start_prev)
  76. begin
  77. divisor <= b;
  78. end
  79. end
  80. always @(posedge clk) begin
  81. if (rst) begin
  82. r_quotient <= 0;
  83. r_dividend_sign <= 0;
  84. r_remainder <= 0;
  85. r_divisor <= 0;
  86. r_count <= 0;
  87. r_ready <= 1'b1;
  88. r_signed_ope <= 1'b0;
  89. end else begin
  90. if (flush) begin
  91. r_count <= 0;
  92. r_ready <= 1'b1;
  93. end else if (start && !start_prev) // use b for this first cycle, as divisor are latched during this cycle
  94. begin
  95. // RISC-V's div by 0 spec
  96. if (b == 0) begin
  97. r_quotient <= 1;
  98. r_remainder <= {w_dividend_sign, dividend};
  99. end else begin
  100. r_quotient <= dividend;
  101. r_remainder <= {(DATA_WIDTH+1){w_dividend_sign}};
  102. r_ready <= 1'b0;
  103. end
  104. r_count <= 0;
  105. r_dividend_sign <= w_dividend_sign;
  106. r_divisor <= b;
  107. r_signed_ope <= signed_ope;
  108. end else if (~ready) begin
  109. r_quotient <= {r_quotient[DATA_WIDTH-2:0], ~diff_sign};
  110. r_remainder <= sub_add[DATA_WIDTH:0];
  111. r_count <= r_count + 1;
  112. if (r_count == DATA_WIDTH - 1) begin
  113. r_ready <= 1'b1;
  114. end
  115. end
  116. end
  117. end
  118. endmodule