Continue to Site

# [SOLVED]binary division with vhdl

Status
Not open for further replies.

#### sam93

##### Junior Member level 1
hi, in part of my project I have to divide a 26 bit binary variable to 19 bit binary constant. would you help me? language is vhdl. thank you in advanced.
it's my code and doesn't work!

Code VHDL - [expand]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
process (CLK_20M)
constant a : std_logic := "1000111101110000000"; --293760
variable counter: std_logic_vector(25 downto 0) ;  ;--26 bits 67108863
variable count:std_logic_vector(25 downto 0) ;  ;--26 bits
variable rps: std_logic_vector(7 downto 0) ; -- 8 bits 255
begin
if rising_edge(CLK_20M) then
counter:=counter + 1;
if (counter > 20000000) then
counter := (others => '0');
elsif rising_edge(ENCODER_HALLSENSOR_B) then
count := count + 1;
end if;
end if;
rpss := count/a;

Last edited by a moderator:

Division is one of the more complicated basic operations. It makes sense to make use of better implementations when possible.

In this case, you either want to do division by multiplication by a constant, or long division by FSM.

Multiplication by a constant basically does:
Code:
x / y = (x * (2**N / y)) / 2**N
eg, you will find the value (2**N / y) and use this as the multiplier. Then you will multiply this with x. Then you will keep only the msbs that correspond to the integer portion.

Division is one of the more complicated basic operations. It makes sense to make use of better implementations when possible.

In this case, you either want to do division by multiplication by a constant, or long division by FSM.

Multiplication by a constant basically does:
x / y = (x * (2**N / y)) / 2**N
eg, you will find the value (2**N / y) and use this as the multiplier. Then you will multiply this with x. Then you will keep only the msbs that correspond to the integer portion.

hi, could you explain it with vhdl code?

More importantly you need do the following:

1. Forget about all the software concepts you've learned in the past, VHDL is hardware.
3. Draw a schematic of the circuit.
4. Use signals instead of variables until you're very familiar with how signals behave in simulation and how the logic is synthesized.
5. Use only one edge sensitive statement in a nested if statement.

I don't know if it's intentional but the following code:
Code:
 counter:=counter + 1;
if (counter > 20000000) then
counter := (others => '0');
counts from 0 to 20000001 back to 0. I doubt your intention was to count 20,000,002 times. Not sure why, but this is a common type of mistake.

Having the edge sensitive ENCODER_HALLSENSOR_B makes no sense as the process only executes when the clock changes state (besides not being synthesizable into any kind of logic).

actually in this code in want to count number of ENCODER_HALLSENSOR_B's pulses in 1 second.
I used the rising edge of CLK_20M (20 MHz) to counting 0 to 20 millions to create one second and at this time I used another counter (count) to counting ENCODER_HALLSENSOR_B's pulses.
then I need to divide number of ENCODER_HALLSENSOR_B's pulses at 300000 to reach 8 bits value.

ENCODER_HALLSENSOR_B is like a clock and includes pulses.

Last edited by a moderator:

Depending on the ENCODER_HALLSENSOR_B pulse width you would be better off synchronizing it to the 20 MHz and then edge detecting it. If the pulses are narrower than the 50 ns clock period you would want to first pulse extend to something more than the 50 ns period of the 20 MHz and then synchronize it with two FFs and edge detect it. If the pulse width is larger than the 50 ns clock period, then synchronize it with the 2 FFs and edge detect. The edge detect in either case will be 1 40ns wide pulse in the 20 MHz clock domain.

You then use the edge detect pulse as an enable to a pulse counter.

The divide can't be done using / as it's not going to be synthesizable unless the divisor is a power of 2. You will need to use a divide algorithm like non-restoring division, which means the result won't be available immediately.

Regardless you still need to draw a schematic of this before you write code. Newbies to HDL should always draw schematics first, then translate the schematic to VHDL/Verilog based on the coding templates for various circuit elements like FFs, mux, gates.

sam93

### sam93

Points: 2
hi again! I write this code for binary divisiona and value dividend and divisor. after simulation in ISE the quotient was wrong. would you help me wha's wrong with this code? thank you.

Code VHDL - [expand]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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_unSIGNED.ALL;
use ieee.numeric_std.all;
use work.asci_types.all;

entity dc1 is

port (CLK_20M: in std_logic;
dividend: in std_logic_vector(25 downto 0):="00000001001001001111100000";
divisor: in std_logic_vector(18 downto 0):="1001001001111100000";

quotient: out std_logic_vector(7 downto 0));
end dc1;
architecture Behavioral of dc1 is

signal a: std_logic_vector(25 downto 0);
signal b: std_logic_vector(18 downto 0);
signal q: std_logic_vector(7 downto 0);

begin
a<= dividend;
b <= divisor;
div_3: Process (CLK_20M,a,b)
variable d: std_logic_vector(18 downto 0);
variable c: std_logic_vector(7 downto 0);
variable temp: std_logic_vector(19 downto 0);
Begin

if (a(25 downto 7) > b) then --7
d:= a(25 downto 7) - b;
c(7) := '1';
else
C(7) := '0';
temp := (a(25 downto 7) & a(6));
d:= (temp - b);

end if;
if (d > b) then --6
c(6) := '1';
d:= d-b;
else
C(6) := '0';
temp := (d & a(5));
d:= temp-b;
end if;
if (d>b) then --5
c(5) := '1';
d:= d-b;
else
C(5) := '0';
temp := (d & a(4));
d:= temp-b;
end if;
if (d>b) then --4
c(4) := '1';
d:=d-b;
else
C(4) := '0';
temp := (d & a(3));
d:= temp-b;
end if;
if (d>b) then --3
c(3) := '1';
d:= d-b;
else
C(3) := '0';
temp := (d & a(2));
d:= temp-b;
end if;
if (d>b) then --2
c(2) := '1';
d:= d-b;
else
C(2) := '0';
temp := (d & a(1));
d:= temp-b;
end if;
if (d > b) then --1
c(1) := '1';
d:=d-b;
else
C(1) := '0';
temp := (d & a(0));
d:= temp-b;
end if;
if (d>b) then --0
c(0) := '1';
else
C(0) := '0';
end if;

quotient <= c;
end process;

End Behavioral;

the test bench code is:

Code VHDL - [expand]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
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

use IEEE.STD_LOGIC_unSIGNED.ALL;
use ieee.numeric_std.all;
use work.asci_types.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;

ENTITY test IS
END test;

ARCHITECTURE behavioral OF test IS

-- Component Declaration for the Unit Under Test (UUT)

COMPONENT dc1
PORT(
CLK_20M : IN  std_logic;
dividend : IN  std_logic_vector(25 downto 0):="00000001001001001111100000";
divisor : IN  std_logic_vector(18 downto 0):="1001001001111100000";
quotient : OUT  std_logic_vector(7 downto 0)
);
END COMPONENT;

--Inputs
signal dividend: std_logic_vector(25 downto 0):="00000001001001001111100000";
signal divisor: std_logic_vector(18 downto 0):="1001001001111100000";
signal quotient: std_logic_vector(7 downto 0);
signal CLK_20M : std_logic := '0';

-- Clock period definitions
constant CLK_20M_period : time := 50 ns;

BEGIN

-- Instantiate the Unit Under Test (UUT)
uut: dc1 PORT MAP (
CLK_20M => CLK_20M,
dividend => dividend,
divisor => divisor,
quotient => quotient
);

-- Clock process definitions
CLK_20M_process :process
begin
CLK_20M <= '0';
wait for CLK_20M_period/2;
CLK_20M <= '1';
wait for CLK_20M_period/2;
end process;

-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 500 ns;

wait for CLK_20M_period*10;

-- insert stimulus here

wait;
end process;

END behavioral;

Last edited by a moderator:

I'm not going to debug your code for you, especially as you haven't shown that you've done anything besides...
"Oh I'll put some long binary values into the dividend and divisor and look at the quotient result. Darn the quotient is wrong, I'll post on edaboard and have a forum member debug my broken code."

It's better if you debug your code. You'll actually learn how to debug if you do that. As you are still using variables (did you read post #4, I told you to not use them) you're going to have problems with displaying them in the waveform window. I seldom use variables, so I'm not sure if this is still the case with Modelsim (I know for a fact there is no way to display them in Vivado's xsim).

Use signals instead, you can code anything you need without using variables, I've been doing this for decades and I use variables for only specific things, mostly for the improved simulation performance as I work with extremely large designs.

Once you have everything displayable then start running the simulation and debug why the calculation comes out wrong by looking at what each step does in the simulation and if it's right. That is all any of us would do, so learn how to do it yourself.

hi ads-ee! As you said I changed variables to signals, but simulation could not be complete!! I faced to this message "ERROR: In process dc1.vhd:div_3
Target Size 20 and source size 21 for array dimension 0 does not match."
and the quotient is not correct yet!

Code VHDL - [expand]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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_unSIGNED.ALL;
use ieee.numeric_std.all;
use work.asci_types.all;

entity dc1 is
generic ( n: integer :=7);
port (CLK_20M: in std_logic;
dividend: in std_logic_vector(25 downto 0):="01111111111111111111111111";
divisor: in std_logic_vector(19 downto 0):="01001001001111100000";

quotient: out std_logic_vector(7 downto 0));
end dc1;
architecture Behavioral of dc1 is

signal a: std_logic_vector(25 downto 0);
signal b: std_logic_vector(19 downto 0);
signal q: std_logic_vector(7 downto 0);
signal d: std_logic_vector(19 downto 0);
begin
a<= dividend;
b <= divisor;
div_3: Process (a,b)

Begin

if (a(25 downto 7) > b) then --7
d<= (a(25 downto 7)- b);
q(n) <= '1';
else
q(n)  <= '0';
d<= (a(25 downto 6) -b);
end if;
if (d>b) then --6
q(n-1) <= '1';
d<= d-b;
else
q(n-1)  <= '0';

d<= (d & a(n-2) -b);

end if;
if (d>b) then --5
q(n-2) <= '1';
d<= d-b;
else
q(n-2)  <= '0';

d<= (d & a(n-3) -b);

end if;
if (d>b) then --4
q(n-3)<= '1';
d<= d-b;
else
q(n-3)  <= '0';

d<= (d & a(n-4) -b);

end if;
if (d>b) then --3
q(n-4) <= '1';
d<= d-b;
else
q(n-4)  <= '0';

d<= (d & a(n-5) -b);

end if;
if (d>b) then --2
q(n-5) <= '1';
d<= d-b;
else
q(n-5)  <= '0';

d<= (d & a(n-6) -b);

end if;
if (d>b) then --1
q(n-6) <= '1';
d<= d-b;
else
q(n-6)  <= '0';

d<= (d & a(n-7) -b);

end if;
if (d>b) then --0
q(n-7)<= '1';

else
q(n-7) <= '0';

end if;

end process;
quotient <= q;
End Behavioral;

Last edited by a moderator:

hi ads-ee! As you said I changed variables to signals, but simulation could not be complete!! I faced to this message "ERROR: In process dc1.vhd:div_3
Target Size 20 and source size 21 for array dimension 0 does not match."
and the quotient is not correct yet!

Code VHDL - [expand]1
2
3
4
5
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_unSIGNED.ALL;
use ieee.numeric_std.all;
use work.asci_types.all;

Because you didn't take into account that you are performing mathematical calculations on the RHS and assigning them to the LHS which is 20-bits. VHDL unlike Verilog requires that the width of the RHS calculation result be the same width as the LHS.

You shouldn't be doing "math" with std_logic_vector. You should be using an unsigned type in the numeric_std package and get rid of the std_logic_unsigned (which is only a de-facto standard package from Synopsys)

I also get the feeling you don't know that all the if statements do not execute in order like software programs. The if statements you have in this process are run in parallel. Therefore d is not defined for all of the if statements. It's obvious that you didn't draw a schematic of you circuit before writing code. VHDL is not software, you use it to describe a circuit, so don't start by writing code draw a schematic of the circuit, then describe that circuit it in VHDL.

sam93

Points: 2