除法器基本思路
对于变量输入的除法中,使用最基础的除法器[^1]。
对于更加具体的除法器的设计可以采用更加灵活的方案:
例如:设计 X / 24 的除法器时,将其分解为 X / 8 * (1 / 4 + 1 / 16 + 1/64 + ···)的形式。,通过加法和移位操作进行处理[^2]。对于其他的被除数,都可以表示为1 / 2 ^ a 的形式进行处理。
跟多的除法器的原理参见一些Stanford的内容[^ 3]。
除法器的实现
关于除法器的设计过程,非常地不顺利,并且第一次设计出来的方案也并不好。这主要是由于读别人的代码少了,输入不够,导致自己的输出并没能达到老师的要求。最后,通过查阅StackOverflow等网站的文章,勉强搞定了设计。这里简单总结一下经验教训:
- 思考要谨慎,不要因为一时的得失而忘形或失意。
- 做事之前一定要有相关的输入,借鉴和思考别人的经验
- 时间安排要合理一些
最后方案
A / 24 = A / 8 / 3 = A / 8 * (1 / 4 + 1/ 16 + 1 / 64 + ··· ) = A >> 3 * ( A >> 2 + A >> 4 + A >> 6 ···) = A >> 5 + A >> 7 + A >> 9 ···
最后注意24的整数倍时存在一个舍入误差即可;verilog中的reg并不是一定是寄存器register,其只是一个存储单元,可以改变內部值,相当于是一个变量。
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| `timescale 1ns / 1ps
module div_24#( parameter DW = 12, parameter RW = 5 )( input clk_i, input rst_n_i, input valid_i, input [DW - 1 : 0] d_i, output reg div_busy_o, output reg valid_o, output [DW - 1 : 0] result_o, output [DW-1 : 0] remainder_o ); reg [2*DW - 1 : 0] d = 0; reg [DW - 1:0] remainder_origin = 0; wire [DW - 1:0] remainder; wire [2*DW-1 : 0] result; always @(posedge clk_i) begin if (!rst_n_i) begin d <= 0; div_busy_o <= 0; end else if (valid_i && !div_busy_o) begin d[2*DW - 1 : DW] <= d_i + 1'b1; div_busy_o <= 1'b1; end else if (div_busy_o) begin div_busy_o <= 1'b0; end end assign result = ( d >> 5 ) + ( d >> 7 ) + ( d >> 9 ) + ( d >> 11 ) + ( d >> 13 ) + ( d >> 15 ); assign result_o = result[2*DW-1 : DW]; always @(*) begin if (!rst_n_i) begin remainder_origin = 0; end else begin remainder_origin = result[2*DW-1 : DW]; end end assign remainder = d[2*DW-1:DW] - (remainder_origin << 3) + ~(remainder_origin << 4); assign remainder_o = remainder[DW - 1:0]; always @(posedge clk_i) begin if (div_busy_o) begin valid_o <= 1'b1; end else begin valid_o <= 1'b0; end end endmodule
|
参考文献
[^1]: Division in Verilog | Project F - FPGA Development
[^2]: vhdl - Easy way of dividing an integer by 3 - Stack Overflow
[^ 3]: Bit Twiddling Hacks (stanford.edu)
其他:Is it possible to shift more than 1 bit per cycle in verilog? - Stack Overflow