├── .gitattributes ├── .gitignore ├── README.md ├── diagram.PNG ├── divfunc.v └── tb.v /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail cache files 2 | Thumbs.db 3 | ehthumbs.db 4 | ehthumbs_vista.db 5 | 6 | # Folder config file 7 | Desktop.ini 8 | 9 | # Recycle Bin used on file shares 10 | $RECYCLE.BIN/ 11 | 12 | # Windows Installer files 13 | *.cab 14 | *.msi 15 | *.msm 16 | *.msp 17 | 18 | # Windows shortcuts 19 | *.lnk 20 | 21 | # ========================= 22 | # Operating System Files 23 | # ========================= 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # verilog-divider 2 | 3 | 4 | ## Principle ## 5 | 6 | ![diagram](https://github.com/risclite/verilog-divider/blob/master/diagram.PNG) 7 | 8 | Divider is an iteration of a serial operation of shift and subtraction. 9 | 10 | Here is the main code of this operation: 11 | 12 | ```verilog 13 | wire [i:0] m = dividend[i]>>(XLEN-i-1); 14 | 15 | wire [i:0] n = divisor[i]; 16 | 17 | wire q = (|(divisor[i]>>(i+1))) ? 1'b0 : ( m>=n ); 18 | 19 | wire [i:0] t = q ? (m - n) : m; 20 | 21 | wire [XLEN-1:0] u = dividend[i]<<(i+1); 22 | 23 | wire [XLEN+i:0] d = {t,u}>>(i+1); 24 | ``` 25 | 26 | "m" is the shift result of dividend. 27 | 28 | "n" is the shift result of divisor. 29 | 30 | "q" is the comparison result, which is the "XLEN-i-1" bit of quotient. 31 | 32 | "d" is the remainder of this operation or the dividend of the next operation. 33 | 34 | Every iteration we get one bit of quotient. Every iteration is the operation of "i"-length subtraction. So the whole calcuation is a serial of XLEN incremental-length subtractions, which are from 1 to XLEN. 35 | 36 | ## divfunc.v ## 37 | 38 | Two parameters: 39 | * XLEN --- the length of operators, such as 8,16,32,64. take 32 as an example. 40 | 41 | * STAGE_LIST --- To put one register after the subtraction. For examples: 42 | 43 | 32'b0000_0000_0000_0000_0000_0000_0000_0000 : the longest critical path: a chain of "1+2+3+...32"-length subtractions. 44 | 45 | 32'b0000_0000_0000_0001_0000_0000_1000_0001 : there "1" means there stages. a chain of "1+2+3+...16" is the first stage; "17+...25" is the second stage; 26+27+...32" is the third stage. 46 | 47 | 48 | Input ports: 49 | 50 | * a (bit length is XLEN) : dividend 51 | 52 | * b (bit length is XLEN) : divisor 53 | 54 | * vld ( bit length is 1) : valid signal of this operation. "1" is valid. 55 | 56 | 57 | output ports: 58 | 59 | * quo (bit length is XLEN) : quotient 60 | 61 | * rem (bit length is XLEN) : remainder 62 | 63 | * ack ( bit length is 1) : acknowledge signal corresponds with "vld". It depends how many stages you put with "STAGE_LIST". 64 | 65 | 66 | ## tb.v ## 67 | 68 | A simple verilog testbench file to verify "divfunc.v". 69 | 70 | ## How to use this divfunc.v ## 71 | 72 | First please set STAGE_LIST to all-zero. You get a long critical path: N for (1+2+3+...+32 subtractions). You name an assumed critical path: M. Try to set "STAGE_LIST" with "1" in different bit poisition until your new ciritical path is less than M. 73 | 74 | For example: A synthesis on DE2-115 FPGA: 75 | 76 | STAGE_LIST is 32'b0: We get that a critical path is 110 ns. 77 | 78 | My assumed critical path is 25 ns. I will try to set STAGE_LIST to 32'b0000_0000_1000_0001_0000_0010_0001_0001. 79 | 80 | It is not linear and try to make even. It is possible to use only 5~6 stages to complete a 32 bit/32 bit calculation. 81 | 82 | -------------------------------------------------------------------------------- /diagram.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/risclite/verilog-divider/e73dec16750b45bd9e01d82848251e564a4d5354/diagram.PNG -------------------------------------------------------------------------------- /divfunc.v: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | //Copyright 2019 Li Xinbing 4 | // 5 | //Licensed under the Apache License, Version 2.0 (the "License"); 6 | //you may not use this file except in compliance with the License. 7 | //You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | //Unless required by applicable law or agreed to in writing, software 12 | //distributed under the License is distributed on an "AS IS" BASIS, 13 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //See the License for the specific language governing permissions and 15 | //limitations under the License. 16 | // 17 | ///////////////////////////////////////////////////////////////////////////////////// 18 | 19 | `define N(n) [(n)-1:0] 20 | `define FFx(signal,bits) always @ ( posedge clk or posedge rst ) if ( rst ) signal <= bits; else 21 | 22 | module divfunc 23 | #( 24 | parameter XLEN = 32, 25 | parameter `N(XLEN) STAGE_LIST = 0 26 | ) 27 | ( 28 | 29 | input clk, 30 | input rst, 31 | 32 | input `N(XLEN) a, 33 | input `N(XLEN) b, 34 | input vld, 35 | 36 | 37 | output `N(XLEN) quo, 38 | output `N(XLEN) rem, 39 | output ack 40 | 41 | ); 42 | 43 | reg ready `N(XLEN+1); 44 | reg `N(XLEN) dividend `N(XLEN+1); 45 | reg `N(XLEN) divisor `N(XLEN+1); 46 | reg `N(XLEN) quotient `N(XLEN+1); 47 | 48 | always@* begin 49 | ready[0] = vld; 50 | dividend[0] = a; 51 | divisor[0] = b; 52 | quotient[0] = 0; 53 | end 54 | 55 | generate 56 | genvar i; 57 | for (i=0;i>(XLEN-i-1); 60 | 61 | wire [i:0] n = divisor[i]; 62 | 63 | wire q = (|(divisor[i]>>(i+1))) ? 1'b0 : ( m>=n ); 64 | 65 | wire [i:0] t = q ? (m - n) : m; 66 | 67 | wire [XLEN-1:0] u = dividend[i]<<(i+1); 68 | 69 | wire [XLEN+i:0] d = {t,u}>>(i+1); 70 | 71 | if (STAGE_LIST[XLEN-i-1]) begin:gen_ff 72 | `FFx(ready[i+1],0) 73 | ready[i+1] <= ready[i]; 74 | 75 | `FFx(dividend[i+1],0) 76 | dividend[i+1] <= d; 77 | 78 | `FFx(divisor[i+1],0) 79 | divisor[i+1] <= divisor[i]; 80 | 81 | `FFx(quotient[i+1],0) 82 | quotient[i+1] <= quotient[i]|(q<<(XLEN-i-1)); 83 | 84 | end else begin:gen_comb 85 | always @* begin 86 | ready[i+1] = ready[i]; 87 | dividend[i+1] = d; 88 | divisor[i+1] = divisor[i]; 89 | quotient[i+1] = quotient[i]|(q<<(XLEN-i-1)); 90 | end 91 | end 92 | end 93 | endgenerate 94 | 95 | assign quo = quotient[XLEN]; 96 | 97 | assign rem = dividend[XLEN]; 98 | 99 | assign ack = ready[XLEN]; 100 | 101 | endmodule 102 | 103 | 104 | -------------------------------------------------------------------------------- /tb.v: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | //Copyright 2019 Li Xinbing 4 | // 5 | //Licensed under the Apache License, Version 2.0 (the "License"); 6 | //you may not use this file except in compliance with the License. 7 | //You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | //Unless required by applicable law or agreed to in writing, software 12 | //distributed under the License is distributed on an "AS IS" BASIS, 13 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //See the License for the specific language governing permissions and 15 | //limitations under the License. 16 | // 17 | ///////////////////////////////////////////////////////////////////////////////////// 18 | 19 | `define N(n) [(n)-1:0] 20 | `define FFx(signal,bits) always @ ( posedge clk or posedge rst ) if ( rst ) signal <= bits; else 21 | 22 | `define PERIOD 10 23 | `define XLEN 32 24 | `define DEL 2 25 | module tb; 26 | 27 | reg clk = 0; 28 | always clk = #(`PERIOD/2) ~clk; 29 | 30 | reg rst = 1'b1; 31 | initial #(`PERIOD) rst = 1'b0; 32 | 33 | reg `N(`XLEN) dividend = 0, divisor =0, quotient, remainder; 34 | reg vld = 1'b0; 35 | 36 | wire ack; 37 | wire `N(`XLEN) quo,rem; 38 | 39 | localparam STAGE_LIST = 32'h0101_0101;//32'b00000000_00000000_00000000_00000000; 40 | 41 | function `N($clog2(`XLEN+1)) bitcount( input `N(`XLEN) n); 42 | integer i; 43 | begin 44 | bitcount = 0; 45 | for (i=0;i<`XLEN;i=i+1) 46 | bitcount = bitcount + n[i]; 47 | end 48 | endfunction 49 | 50 | wire `N($clog2(`XLEN+1)) stage_num = bitcount(STAGE_LIST); 51 | 52 | divfunc 53 | #( 54 | .XLEN ( `XLEN ), 55 | .STAGE_LIST ( STAGE_LIST ) 56 | 57 | ) i_div ( 58 | .clk ( clk ), 59 | .rst ( rst ), 60 | 61 | .a ( dividend ), 62 | .b ( divisor ), 63 | .vld ( vld ), 64 | 65 | .quo ( quo ), 66 | .rem ( rem ), 67 | .ack ( ack ) 68 | 69 | ); 70 | 71 | 72 | task one_div_operation( 73 | input `N(32) a,b 74 | ); 75 | begin 76 | dividend = a; 77 | divisor = b; 78 | quotient = a/b; 79 | remainder = a%b; 80 | $display("---ONE DIV OPERATION: dividend=%h, divisor=%h, quotient=%h, remainder=%h",dividend,divisor,quotient,remainder); 81 | 82 | @(posedge clk); 83 | #`DEL vld = 1'b1; 84 | @(posedge clk); 85 | if ( stage_num!=0 ) begin 86 | #`DEL vld = 1'b0; 87 | repeat(stage_num-1'b1) begin 88 | @(posedge clk); 89 | #`DEL vld = 1'b0; 90 | end 91 | @(posedge clk ); 92 | end 93 | check_response; 94 | #`DEL vld = 1'b0; 95 | end 96 | endtask 97 | 98 | 99 | task check_response; 100 | begin 101 | if ( ack & (quo==quotient) & (rem==remainder) ) begin 102 | $display($time," ns---RESPONSE OK---"); 103 | end else begin 104 | $display($time," ns---RESPONSE ERROR---"); 105 | $stop(1); 106 | end 107 | end 108 | endtask 109 | 110 | initial begin: initial_main 111 | reg `N(`XLEN) a,b; 112 | repeat(100) begin 113 | a = $random; 114 | b = $random; 115 | one_div_operation(a,b); 116 | end 117 | repeat(100) begin 118 | a = $random; 119 | b = $random & 8'hff; 120 | one_div_operation(a,b); 121 | end 122 | $display("---Verified OK---"); 123 | $stop(1); 124 | end 125 | 126 | 127 | 128 | endmodule --------------------------------------------------------------------------------