├── image.png ├── SRT2 ├── q_sel.v ├── find_1.v ├── tb_srt.v └── SRT2.v ├── SRT4 ├── find_1.v ├── tb_srt.v ├── q_sel.v └── SRT4.v └── README.md /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/out-of-order55/SRT-Divider/HEAD/image.png -------------------------------------------------------------------------------- /SRT2/q_sel.v: -------------------------------------------------------------------------------- 1 | module q_sel #( 2 | parameter WIDTH = 8 3 | ) ( 4 | rem , 5 | d , 6 | q , 7 | neg 8 | ); 9 | input[2:0] rem; 10 | input d; 11 | output reg q; 12 | output neg; 13 | 14 | always @(*) begin 15 | if(rem<3'b010|rem>=3'b110)begin 16 | q = 1'b0; 17 | end 18 | else begin 19 | q = 1'b1; 20 | end 21 | end 22 | assign neg = q&(d!=rem[2]); 23 | endmodule -------------------------------------------------------------------------------- /SRT2/find_1.v: -------------------------------------------------------------------------------- 1 | module find_1# 2 | ( 3 | parameter WID=8 4 | ) 5 | ( 6 | d_i , 7 | pos_o 8 | ); 9 | input [WID-1:0] d_i; 10 | output reg[WID-1:0] pos_o; 11 | 12 | wire [WID-1:0] pos_oh; 13 | 14 | reg [WID-1:0] op_t;//one hot 15 | integer i; 16 | always @(*) begin 17 | for(i=0; i 8 | 知乎的这篇文章将SRT需要知道的前置知识总结了一下,不过大概率看不懂,没关系,还有一个链接
9 | 2.https://zhuanlan.zhihu.com/p/550913605
10 | 这个链接主要讲解了SRT除法的实现,如果仅仅想实现SRT除法,强推这个链接
11 | 如果真的想读懂SRT,建议搜索A New Class of Digital Division Methods,这篇论文是SRT算法的源论文之一,另一篇全是数学推导 12 | ## 实现细节 13 | 主要有四个模块:QDS表,找1模块,on-the-fly conversion和DIV状态机 14 | ### QDS 表 15 | 见链接2或3,选择任意一个实现即可 16 | ### 找1模块 17 | 网上很多资料了,本人采用的one hot码实现 18 | ### on-the-fly 19 | 在看完上面两个链接后,你可能觉得还是不太懂,并且也没说on-the-fly怎么实现
20 | 3.https://www.cnblogs.com/devindd/articles/17633558.html
21 | 这个链接列出了on-the-fly的实现公式,并且给出了SRT4除法的QDS表一种选择方法
22 | 我自己是按照第二个链接给的QDS表实现的,在实现中,发现-2,-1,0,1,2的边界商的取值也不能乱选(可以看看当选择的table为15时,有一部分范围会重叠),对于这些部分,其可供选择的商就有两个,比如部分余数的前六位为-4,这时候既可以选择1,也可以选择0,但我建议选择1,有时候选择0会导致之后的步骤部分余数前六位超出QDS表的范围(实现中在高位商遇到该问题,选择0导致输出最大也达不到正确的值) 23 | ### DIV状态机 24 | 25 | ![alt text](image.png)
26 | 27 | 图上未标出转换条件即为下周期就跳转状态,下面介绍每个状态的含义 28 | **IDLE**:DIV初始状态,等待valid信号输入 29 | **DIV_1**:除数为1,这时有些table商选择范围会超出QDS表,导致计算出错,故单独列一个状态计算除数为1的情况 30 | **DIV_ERROR**:除数为0,拉高error信号 31 | **DIV_PRE**:寄存除数被除数,得出到底该使用QDS表的哪个table 32 | **DIV_WORKING**:除法器运行状态,当div_cnt为0时结束运行,div_cnt的初始值即为迭代次数,对于SRT4来说,迭代次数为位宽的1/2 33 | **DIV_END**:对得到的商和余数做后处理,查看余数正负性,生成ready信号 34 | ## 仿真 35 | 先生成正确的商和余数,然后等自己的除法器计算完成后进行对比,如果错误则停止仿真。 36 | ## 其他参考资料 37 | https://zhuanlan.zhihu.com/p/445439418
38 | COMPUTER ARITHMETIC Algorithms and Hardware Designs:这本书介绍了许多高级的乘除法算法 39 | Higher-Radix Division Using Estimates of the Divisor and Partial Remainders:对高基SRT算法的分析论文 40 | -------------------------------------------------------------------------------- /SRT2/tb_srt.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | module tb_srt(); 3 | parameter WID=64; 4 | reg clk; 5 | reg rst; 6 | wire[WID-1:0] rem_ref; 7 | wire[WID-1:0] q_ref; 8 | wire[WID-1:0] rem_d; 9 | wire[WID-1:0] q_d; 10 | reg[WID-1:0] dividend; 11 | reg start; 12 | reg[WID-1:0] divisor; 13 | reg valid; 14 | parameter MAX_NUM = 64'hffffffffff; 15 | parameter MIN_NUM = 64'hffffff; 16 | 17 | initial begin 18 | clk <= 1'b0; 19 | rst <= 1'b1; 20 | start <= 1'b0; 21 | #60 22 | rst <= 1'b0; 23 | #20 24 | start <= 1'b1; 25 | #20 26 | start <= 1'b0; 27 | end 28 | always #10 clk <= ~clk; 29 | always @(posedge clk) begin 30 | if(rst)begin 31 | dividend <= 'b1; 32 | divisor <= 'b1; 33 | valid <= 'b0; 34 | end 35 | else if(start)begin 36 | dividend <= MIN_NUM + {$random()} % (MAX_NUM-MIN_NUM+1); 37 | divisor <= {$random()} % MIN_NUM+1; 38 | valid <= 1'b1; 39 | end 40 | else if(ready)begin 41 | dividend <= MIN_NUM + {$random()} % (MAX_NUM-MIN_NUM+1); 42 | divisor <= {$random()} % MIN_NUM+1; 43 | valid <= 1'b1; 44 | end 45 | else begin 46 | valid <= 1'b0; 47 | end 48 | end 49 | assign rem_ref = dividend%divisor; 50 | assign q_ref = dividend/divisor; 51 | always @(*) begin 52 | if(ready)begin 53 | if((rem_ref!=rem_d)|(q_ref!=q_d))begin 54 | $stop; 55 | end 56 | end 57 | end 58 | wire ready; 59 | SRT2 #( 60 | .WID(WID) 61 | ) SRT2( 62 | .clk (clk), 63 | .rst (rst), 64 | .dividend (dividend), 65 | .divisor (divisor), 66 | .valid (valid), 67 | .ready (ready), 68 | .quotient (q_d), 69 | .remainder (rem_d) 70 | ); 71 | endmodule -------------------------------------------------------------------------------- /SRT4/tb_srt.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | module tb_srt(); 3 | parameter WID=64; 4 | reg clk; 5 | reg rst; 6 | wire signed[WID-1:0] rem_ref; 7 | wire signed[WID-1:0] q_ref; 8 | wire[WID-1:0] rem_d; 9 | wire[WID-1:0] q_d; 10 | reg signed[WID-1:0] dividend; 11 | reg start; 12 | reg signed[WID-1:0] divisor; 13 | reg valid; 14 | parameter MAX_NUM = 64'hffffffffffffffff; 15 | parameter MIN_NUM = 64'h7fffffffffffffff; 16 | 17 | initial begin 18 | clk <= 1'b0; 19 | rst <= 1'b1; 20 | start <= 1'b0; 21 | #60 22 | rst <= 1'b0; 23 | #20 24 | start <= 1'b1; 25 | #20 26 | start <= 1'b0; 27 | end 28 | always #10 clk <= ~clk; 29 | always @(posedge clk) begin 30 | if(rst)begin 31 | dividend <= 'b1; 32 | divisor <= 'b1; 33 | valid <= 'b0; 34 | end 35 | else if(start)begin 36 | dividend <= MIN_NUM + {$random()} % (MAX_NUM-MIN_NUM+1); 37 | divisor <= {$random()} % MIN_NUM+1; 38 | valid <= 1'b1; 39 | end 40 | else if(ready)begin 41 | dividend <= MIN_NUM + {$random()} % (MAX_NUM-MIN_NUM+1); 42 | divisor <= {$random()} % MIN_NUM+1; 43 | valid <= 1'b1; 44 | end 45 | else begin 46 | valid <= 1'b0; 47 | end 48 | end 49 | assign rem_ref = dividend%divisor; 50 | assign q_ref = dividend/divisor; 51 | always @(*) begin 52 | if(ready)begin 53 | if((rem_ref!=rem_d)|(q_ref!=q_d))begin 54 | $stop; 55 | end 56 | end 57 | end 58 | wire ready; 59 | SRT4 #( 60 | .WID(WID) 61 | ) SRT4( 62 | .clk (clk), 63 | .rst (rst), 64 | .dividend (dividend), 65 | .divisor (divisor), 66 | .sign (1'b1), 67 | .valid (valid), 68 | .ready (ready), 69 | .quotient (q_d), 70 | .remainder (rem_d) 71 | ); 72 | endmodule -------------------------------------------------------------------------------- /SRT4/q_sel.v: -------------------------------------------------------------------------------- 1 | module q_sel #( 2 | parameter WIDTH = 8 3 | ) ( 4 | rem , 5 | d , 6 | q , 7 | neg 8 | ); 9 | input[5:0] rem; 10 | input[3:0] d; 11 | output[1:0] q; 12 | output neg; 13 | 14 | wire table_8,table_9,table_10,table_11,table_12,table_13,table_14,table_15; 15 | 16 | assign table_8 = d==4'b1000; 17 | assign table_9 = d==4'b1001; 18 | assign table_10 = d==4'b1010; 19 | assign table_11 = d==4'b1011; 20 | assign table_12 = d==4'b1100; 21 | assign table_13 = d==4'b1101; 22 | assign table_14 = d==4'b1110; 23 | assign table_15 = d==4'b1111; 24 | wire q2 ; 25 | wire q0 ; 26 | 27 | assign neg = 28 | table_8 &&(rem>=6'b110100&&rem<6'b111110) 29 | ||table_9 &&(rem>=6'b110010&&rem<6'b111101) 30 | ||table_10&&(rem>=6'b110001&&rem<6'b111101) 31 | ||table_11&&(rem>=6'b110000&&rem<6'b111101) 32 | ||table_12&&(rem>=6'b101110&&rem<6'b111100) 33 | ||table_13&&(rem>=6'b101101&&rem<6'b111100) 34 | ||table_14&&(rem>=6'b101100&&rem<6'b111100) 35 | ||table_15&&(rem>=6'b101010&&rem<6'b111100); 36 | assign q2 = 37 | table_8 &&((rem>=6'b110100&&rem<6'b111010)||(rem>=6'b000110&&rem<=6'b001011)) 38 | ||table_9 &&((rem>=6'b110010&&rem<6'b111001)||(rem>=6'b000111&&rem<=6'b001101)) 39 | ||table_10&&((rem>=6'b110001&&rem<6'b111000)||(rem>=6'b001000&&rem<=6'b001110)) 40 | ||table_11&&((rem>=6'b110000&&rem<6'b110111)||(rem>=6'b001000&&rem<=6'b001111)) 41 | ||table_12&&((rem>=6'b101110&&rem<6'b110110)||(rem>=6'b001001&&rem<=6'b010001)) 42 | ||table_13&&((rem>=6'b101101&&rem<6'b110110)||(rem>=6'b001010&&rem<=6'b010010)) 43 | ||table_14&&((rem>=6'b101100&&rem<6'b110101)||(rem>=6'b001010&&rem<=6'b010011)) 44 | ||table_15&&((rem>=6'b101010&&rem<6'b110100)||(rem>=6'b001011&&rem<=6'b010101)); 45 | assign q0 = 46 | table_8 &&((rem>=6'b111110&&rem<=6'b111111)|| (rem>=0&&rem<6'b000010)) 47 | ||table_9 &&((rem>=6'b111101&&rem<=6'b111111)||(rem>=0&&rem<6'b000010)) 48 | ||table_10&&((rem>=6'b111101&&rem<=6'b111111)||(rem>=0&&rem<6'b000010)) 49 | ||table_11&&((rem>=6'b111101&&rem<=6'b111111)||(rem>=0&&rem<6'b000010)) 50 | ||table_12&&((rem>=6'b111100&&rem<=6'b111111)||(rem>=0&&rem<6'b000011)) 51 | ||table_13&&((rem>=6'b111100&&rem<=6'b111111)||(rem>=0&&rem<6'b000011)) 52 | ||table_14&&((rem>=6'b111100&&rem<=6'b111111)||(rem>=0&&rem<6'b000011)) 53 | ||table_15&&((rem>=6'b111100&&rem<=6'b111111)||(rem>=0&&rem<6'b000100)); 54 | assign q = q2 ? 2'b10 55 | :q0 ? 2'b00 56 | :2'b01; 57 | endmodule -------------------------------------------------------------------------------- /SRT2/SRT2.v: -------------------------------------------------------------------------------- 1 | module SRT2 #( 2 | parameter WID=8 3 | ) ( 4 | clk , 5 | rst , 6 | dividend , 7 | divisor , 8 | valid , 9 | ready , 10 | quotient , 11 | remainder 12 | ); 13 | input clk; 14 | input rst; 15 | input[WID-1:0] dividend; 16 | input[WID-1:0] divisor; 17 | input valid; 18 | output ready; 19 | output[WID-1:0] quotient; 20 | output[WID-1:0] remainder; 21 | 22 | reg ready_o; 23 | wire[WID-1:0] pos_1; 24 | wire q; 25 | wire neg; 26 | reg[WID-1:0] div_shift; 27 | reg dividend_sign; 28 | always @(posedge clk) begin 29 | if(rst)begin 30 | dividend_sign <= 'b0; 31 | end 32 | else if(valid)begin 33 | dividend_sign <= dividend[WID-1]; 34 | end 35 | end 36 | find_1# 37 | ( 38 | .WID(WID) 39 | ) 40 | find_1( 41 | .d_i (divisor), 42 | .pos_o (pos_1) 43 | ); 44 | q_sel #( 45 | .WIDTH(WID) 46 | )q_sel ( 47 | .rem (shift_rem[WID:WID-2]), 48 | .d (1'b0), 49 | .q (q), 50 | .neg (neg) 51 | ); 52 | always @(posedge clk) begin 53 | if(rst)begin 54 | div_shift <= 'b0; 55 | end 56 | else if(valid)begin 57 | div_shift <= pos_1+2;//to allow op1 in{-1/2,1/2} 58 | end 59 | end 60 | wire[WID+1:0] shift_divisor; 61 | wire[WID+1:0] shift_divisor_n; 62 | reg[WID+1:0] Q; 63 | reg[WID+1:0] QM; 64 | reg[WID+1:0] shift_rem; 65 | reg[WID+1:0] div_cnt; 66 | assign shift_divisor = divisor<>div_shift; 214 | endmodule -------------------------------------------------------------------------------- /SRT4/SRT4.v: -------------------------------------------------------------------------------- 1 | module SRT4 #( 2 | parameter WID=8 3 | ) ( 4 | clk , 5 | rst , 6 | dividend , 7 | divisor , 8 | sign , 9 | valid , 10 | ready , 11 | quotient , 12 | error , 13 | remainder 14 | ); 15 | input clk; 16 | input rst; 17 | input[WID-1:0] dividend; 18 | input[WID-1:0] divisor; 19 | input sign; 20 | input valid; 21 | output error; 22 | output ready; 23 | output[WID-1:0] quotient; 24 | output[WID-1:0] remainder; 25 | 26 | 27 | wire [2*WID:0] rem;//only use [2*WID:WID] 28 | reg ready_o; 29 | wire[WID-1:0] pos_1; 30 | wire[1:0] q; 31 | wire neg; 32 | reg[WID-1:0] div_shift; 33 | reg[WID-1:0] dividend_r; 34 | reg[WID-1:0] divisor_r; 35 | reg[1:0] div_sign;//{dividend,divisor} 36 | reg sign_r; 37 | wire[3:0] qds_table; 38 | wire[WID-1:0] dividend_u; 39 | wire[WID-1:0] divisor_u; 40 | wire[WID:0] shift_divisor_X2; 41 | wire[WID:0] shift_divisor; 42 | wire[WID:0] shift_divisor_X2n; 43 | wire[WID:0] shift_divisor_n; 44 | 45 | reg[WID:0] Q; 46 | reg[WID:0] QM; 47 | reg[2*WID:0] shift_rem; 48 | reg[WID-1:0] shift_dividend; 49 | reg[WID:0] div_cnt; 50 | reg[WID:0] fin_q; 51 | reg[WID:0] fin_rem; 52 | wire[WID:0] q_signed; 53 | wire[WID:0] rem_signed; 54 | wire[WID:0] q_unsigned; 55 | wire[WID:0] rem_unsigned; 56 | reg[2:0] state; 57 | 58 | assign dividend_u = sign&÷nd[WID-1]?(~dividend+1):dividend; 59 | assign divisor_u = sign&&divisor[WID-1]?(~divisor+1):divisor; 60 | always @(posedge clk) begin 61 | if(rst)begin 62 | sign_r <= 'b0; 63 | end 64 | else if(valid&&sign)begin 65 | sign_r <= sign; 66 | end 67 | end 68 | always @(posedge clk) begin 69 | if(rst)begin 70 | dividend_r <= 'b0; 71 | divisor_r <= 'b0; 72 | div_sign <= 'b0; 73 | end 74 | else if(valid)begin 75 | dividend_r <= dividend_u; 76 | divisor_r <= divisor_u; 77 | div_sign <= {dividend[WID-1],divisor[WID-1]}; 78 | end 79 | end 80 | 81 | 82 | find_1# 83 | ( 84 | .WID(WID) 85 | ) 86 | find_1( 87 | .d_i (divisor_u), 88 | .pos_o (pos_1) 89 | ); 90 | q_sel #( 91 | .WIDTH(WID) 92 | )q_sel ( 93 | .rem (shift_rem[2*WID:2*WID-5]), 94 | .d (qds_table), 95 | .q (q), 96 | .neg (neg) 97 | ); 98 | always @(posedge clk) begin 99 | if(rst)begin 100 | div_shift <= 'b0; 101 | end 102 | else if(state==IDLE&&valid)begin 103 | div_shift <= pos_1+1; 104 | end 105 | end 106 | 107 | assign rem = {{(WID+1){0}},dividend_r}<>div_shift)+1):(fin_rem>>div_shift); 247 | assign q_unsigned = fin_q; 248 | assign rem_unsigned = fin_rem>>div_shift; 249 | 250 | assign ready = state==DIV_1?1'b1:ready_o; 251 | assign quotient = state==DIV_1?dividend:(sign_r?q_signed:q_unsigned); 252 | assign remainder= state==DIV_1?1'b0:(sign_r?rem_signed:rem_unsigned); 253 | assign error = state==DIV_ERROR; 254 | endmodule --------------------------------------------------------------------------------