Velocity Reviews > VHDL > Dividing by 48

# Dividing by 48

ALuPin@web.de
Guest
Posts: n/a

 11-08-2006
Hi,

I have a signal (integer). How can I describe synthesizable code
for dividing that signal by 48 ? Result (ls_rowaddr) should
be whole-number that is integer.

SIGNAL ls_pos : integer RANGE 0 TO 8191;
SIGNAL ls_rowaddr : integer RANGE 0 TO 191;

PROCESS(Reset, Clk)
BEGIN
IF Reset='1' THEN
ls_pos <= 0;

ELSIF rising_edge(Clk) THEN
END IF;

END IF;
END PROCESS;

-- synthesis ???
PROCESS(ls_pos)
BEGIN
END IF;

How can 32 (2^5) and 16 (2^4) be combined ?

Rgds
André

wallge
Guest
Posts: n/a

 11-08-2006
factor 48 into (16 * 3)
you can first bit shift to the right by four places then
divide by three using division (division by 3 is much faster than by 48
and requires less logic i suspect)

PROCESS(clk, ls_pos)
variable unsigned_ls_pos : unsigned(12 downto 0);
variable shifted_ls_pos : unsigned(7 downto 0);
BEGIN
if rising_edge(clk) then
unsigned_ls_pos := to_unsigned(ls_pos, 13); --convert to
unsigned
shifted_ls_pos := unsigned_ls_pos(12 downto 4); --chop off
bottom 4 bits same as x/16
ls_rowaddr <= to_integer(shifted_ls_pos / to_unsigned(3, 2));
--divide by 3
END IF;
end process;

use ieee.numeric_std.all as the library for arithmetic
dont use std_logic_unsigned or std_logic_arith,
phased out)

if you have quartus or xilinx ISE this code should synthesize
(i would expect synopsys or synplify as well)

http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> Hi,
>
> I have a signal (integer). How can I describe synthesizable code
> for dividing that signal by 48 ? Result (ls_rowaddr) should
> be whole-number that is integer.
>
> SIGNAL ls_pos : integer RANGE 0 TO 8191;
> SIGNAL ls_rowaddr : integer RANGE 0 TO 191;
>
> PROCESS(Reset, Clk)
> BEGIN
> IF Reset='1' THEN
> ls_pos <= 0;
>
> ELSIF rising_edge(Clk) THEN
> END IF;
>
> END IF;
> END PROCESS;
>
> -- synthesis ???
> PROCESS(ls_pos)
> BEGIN
> ls_rowaddr <= ls_pos / 48;
> END IF;
>
> How can 32 (2^5) and 16 (2^4) be combined ?
>
>
>
>
> Rgds
> André

jens
Guest
Posts: n/a

 11-08-2006
wallge wrote:
> factor 48 into (16 * 3)
> you can first bit shift to the right by four places then
> divide by three using division (division by 3 is much faster than by 48
> and requires less logic i suspect)

Assuming the divide by 48 is to be rounded down, the divide by 3 can be
replaced by * 171 / 512 (shift right by 9) and will yield the desired
result.

ALuPin@web.de
Guest
Posts: n/a

 11-08-2006
Hi wallge,

I get the following error message with SynplifyPro 8.6.2:

Right argument must evaluate to a constant integer power of 2

library ieee;

use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

ENTITY divider IS
PORT( Reset : IN std_logic;
Clk : IN std_logic;
DataIn : IN std_logic_vector(12 DOWNTO 0);
DataOut : OUT std_logic_vector(12 DOWNTO 0)
);
END divider;

ARCHITECTURE rtl OF divider IS

SIGNAL ls_data_out : unsigned(12 DOWNTO 0);

BEGIN

DataOut <= std_logic_vector(ls_data_out);

PROCESS(Reset, Clk)
variable v_data : unsigned(12 DOWNTO 0);
variable v_data_shift : unsigned(8 DOWNTO 0);
BEGIN
IF Reset='1' THEN
ls_data_out <= (OTHERS => '0');

ELSIF rising_edge(Clk) THEN
v_data := unsigned(DataIn);
v_data_shift := unsigned(v_data(12 DOWNTO 4));

ls_data_out <= (v_data_shift / to_unsigned(3,2));

END IF;
END PROCESS;

END rtl;

wallge
Guest
Posts: n/a

 11-08-2006
hmm...
I guess synplify wont do handle division for some reason.
if you have quartus you can instantiate a mega-function divider
component to do the division,
and even choose how many pipe stages are in the divider.

I am pretty sure that xilinx ISE has the same king of thing, i forget
the name of the tool off the top of my head, but i know xilinx also has
customizable arithmetic blocks within ISE that can be instantiated in

(E-Mail Removed) wrote:
> Hi wallge,
>
> I get the following error message with SynplifyPro 8.6.2:
>
>
> Right argument must evaluate to a constant integer power of 2
>
>
> library ieee;
>
> use ieee.std_logic_1164.all;
> use ieee.numeric_std.all;
>
> ENTITY divider IS
> PORT( Reset : IN std_logic;
> Clk : IN std_logic;
> DataIn : IN std_logic_vector(12 DOWNTO 0);
> DataOut : OUT std_logic_vector(12 DOWNTO 0)
> );
> END divider;
>
> ARCHITECTURE rtl OF divider IS
>
>
> SIGNAL ls_data_out : unsigned(12 DOWNTO 0);
>
> BEGIN
>
> DataOut <= std_logic_vector(ls_data_out);
>
> PROCESS(Reset, Clk)
> variable v_data : unsigned(12 DOWNTO 0);
> variable v_data_shift : unsigned(8 DOWNTO 0);
> BEGIN
> IF Reset='1' THEN
> ls_data_out <= (OTHERS => '0');
>
> ELSIF rising_edge(Clk) THEN
> v_data := unsigned(DataIn);
> v_data_shift := unsigned(v_data(12 DOWNTO 4));
>
> ls_data_out <= (v_data_shift / to_unsigned(3,2));
>
> END IF;
> END PROCESS;
>
> END rtl;

Ray Andraka
Guest
Posts: n/a

 11-09-2006
(E-Mail Removed) wrote:

> Hi,
>
> I have a signal (integer). How can I describe synthesizable code
> for dividing that signal by 48 ? Result (ls_rowaddr) should
> be whole-number that is integer.
>
> SIGNAL ls_pos : integer RANGE 0 TO 8191;
> SIGNAL ls_rowaddr : integer RANGE 0 TO 191;
>
> PROCESS(Reset, Clk)
> BEGIN
> IF Reset='1' THEN
> ls_pos <= 0;
>
> ELSIF rising_edge(Clk) THEN
> END IF;
>
> END IF;
> END PROCESS;
>
> -- synthesis ???
> PROCESS(ls_pos)
> BEGIN
> ls_rowaddr <= ls_pos / 48;
> END IF;
>
> How can 32 (2^5) and 16 (2^4) be combined ?
>
>
>
>
> Rgds
> André
>

For division by a constant, instead multiply by the reciprocal of the
divisor (the reciprocal is also a constant). You'll want to scale by a
power of two, which is to say you move the position of the implied radix
point. 1/48 = 0.0208333. To make that an integer, scale it by a power
of 2 that gives an appropriate amount of precision for your task. For
example, you might scale it by 2^16 so your reciprocal is 1365*2^-16.
Then when you multiply the dividend, you wind up with a product that is
also weighted 2^-16, so you need to right shift it 16 places to restore
the scaling of the dividend. The multiply in this case is a repeating
pattern of bits (0x555), which can be done with a tree of adders rather
than a multiplier if you do not have full multipliers available.

ALuPin@web.de
Guest
Posts: n/a

 11-09-2006
Mr Andraka,

> The multiply in this case is a repeating
> pattern of bits (0x555), which can be done with a tree of adders rather
> than a multiplier if you do not have full multipliers available.

be combined ?

Rgds
André

ALuPin@web.de
Guest
Posts: n/a

 11-09-2006
Do you mean the following:

multiplying with 1365 = x555

implies the following

C * 1365 = C * (2^10 + 2^8 + 2^6 + 2^4 + 2^2 + 2^0)

= (C* 2^10) + (C*2^ + ...

where the multiplications can be achieved with shift left operations.

Rgds
André

ALuPin@web.de
Guest
Posts: n/a

 11-09-2006
Hi again,

I have found out that my concept has some fault.
Functional simulation and Timing simulation show both
that I have some kind of offset by one in my result:

I get for example : 6000/48 = 124 (instead of 125)

Is there some kind of rounding error I did not think of.

Here is the code and the corresponding testench:

library ieee;

use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

ENTITY divider48 IS
PORT ( Reset : IN std_logic;
Clk : IN std_logic;
Data2DivBy48 : IN std_logic_vector (12 downto 0);
Data2DivBy48Valid : IN std_logic;
DataDividedOut : OUT std_logic_vector (12 downto 0);
);
END divider48;

ARCHITECTURE rtl OF divider48 IS

SIGNAL ls_shift_data_left10 : unsigned(22 DOWNTO 0);
SIGNAL ls_shift_data_left8 : unsigned(22 DOWNTO 0);
SIGNAL ls_shift_data_left6 : unsigned(22 DOWNTO 0);
SIGNAL ls_shift_data_left4 : unsigned(22 DOWNTO 0);
SIGNAL ls_shift_data_left2 : unsigned(22 DOWNTO 0);
SIGNAL ls_shift_data_left0 : unsigned(22 DOWNTO 0);

SIGNAL ls_sum1, ls_sum2, ls_sum3 : unsigned(22 DOWNTO 0);
SIGNAL ls_sum4, ls_sum5 : unsigned(22 DOWNTO 0);

SIGNAL ls_sum123_valid : std_logic;
SIGNAL ls_sum4_valid : std_logic;
SIGNAL ls_sum5_valid : std_logic;

SIGNAL ls_shift_data_right16 : unsigned(22 DOWNTO 0);
SIGNAL ls_shift_right : std_logic;

BEGIN

ls_shift_data_left0 <= ("0000000000" & unsigned(Data2DivBy4);

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SL10_reg: PROCESS(Reset, Clk)
BEGIN
IF Reset='1' THEN
ls_shift_data_left10 <= (OTHERS => '0');

ELSIF rising_edge(Clk) THEN

IF Data2DivBy48Valid='1' THEN
ls_shift_data_left10(22 DOWNTO 10) <= unsigned(Data2DivBy4;
ls_shift_data_left10(9 DOWNTO 0) <= (OTHERS => '0');
END IF;

END IF;
END PROCESS SL10_reg;

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SL8_reg: PROCESS(Reset, Clk)
BEGIN
IF Reset='1' THEN
ls_shift_data_left8 <= (OTHERS => '0');

ELSIF rising_edge(Clk) THEN

IF Data2DivBy48Valid='1' THEN
ls_shift_data_left8(22 DOWNTO 21) <= (OTHERS => '0');
ls_shift_data_left8(20 DOWNTO <= unsigned(Data2DivBy4;
ls_shift_data_left8(7 DOWNTO 0) <= (OTHERS => '0');
END IF;

END IF;
END PROCESS SL8_reg;

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SL6_reg: PROCESS(Reset, Clk)
BEGIN
IF Reset='1' THEN
ls_shift_data_left6 <= (OTHERS => '0');

ELSIF rising_edge(Clk) THEN

IF Data2DivBy48Valid='1' THEN
ls_shift_data_left6(22 DOWNTO 19) <= (OTHERS => '0');
ls_shift_data_left6(18 DOWNTO 6) <= unsigned(Data2DivBy4;
ls_shift_data_left6(5 DOWNTO 0) <= (OTHERS => '0');
END IF;

END IF;
END PROCESS SL6_reg;

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SL4_reg: PROCESS(Reset, Clk)
BEGIN
IF Reset='1' THEN
ls_shift_data_left4 <= (OTHERS => '0');

ELSIF rising_edge(Clk) THEN

IF Data2DivBy48Valid='1' THEN
ls_shift_data_left4(22 DOWNTO 17) <= (OTHERS => '0');
ls_shift_data_left4(16 DOWNTO 4) <= unsigned(Data2DivBy4;
ls_shift_data_left4(3 DOWNTO 0) <= (OTHERS => '0');
END IF;

END IF;
END PROCESS SL4_reg;

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SL2_reg: PROCESS(Reset, Clk)
BEGIN
IF Reset='1' THEN
ls_shift_data_left2 <= (OTHERS => '0');

ELSIF rising_edge(Clk) THEN

IF Data2DivBy48Valid='1' THEN
ls_shift_data_left2(22 DOWNTO 15) <= (OTHERS => '0');
ls_shift_data_left2(14 DOWNTO 2) <= unsigned(Data2DivBy4;
ls_shift_data_left2(1 DOWNTO 0) <= (OTHERS => '0');
END IF;

END IF;
END PROCESS SL2_reg;

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SUM_reg: PROCESS(Reset, Clk)
BEGIN
IF Reset='1' THEN
ls_sum123_valid <= '0';
ls_sum4_valid <= '0';
ls_sum5_valid <= '0';
ls_sum1 <= (OTHERS => '0');
ls_sum2 <= (OTHERS => '0');
ls_sum3 <= (OTHERS => '0');
ls_sum4 <= (OTHERS => '0');
ls_sum5 <= (OTHERS => '0');

ELSIF rising_edge(Clk) THEN
ls_sum123_valid <= Data2DivBy48Valid;
ls_sum4_valid <= ls_sum123_valid;
ls_sum5_valid <= ls_sum4_valid;

IF ls_sum123_valid='1' THEN
ls_sum1 <= ls_shift_data_left10 + ls_shift_data_left8;
ls_sum2 <= ls_shift_data_left6 + ls_shift_data_left4;
ls_sum3 <= ls_shift_data_left2 + ls_shift_data_left0;
END IF;

IF ls_sum4_valid='1' THEN
ls_sum4 <= ls_sum1 + ls_sum2;
END IF;

IF ls_sum5_valid='1' THEN
ls_sum5 <= ls_sum4 + ls_sum3;
END IF;

END IF;
END PROCESS SUM_reg;

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SR16_reg: PROCESS(Reset, Clk)
BEGIN
IF Reset='1' THEN
ls_shift_data_right16 <= (OTHERS => '0');
ls_shift_right <= '0';

ELSIF rising_edge(Clk) THEN
ls_shift_right <= ls_sum5_valid;

IF ls_shift_right='1' THEN
ls_shift_data_right16(22 DOWNTO 7) <= (OTHERS => '0');
ls_shift_data_right16(6 DOWNTO 0) <= ls_sum5(22 DOWNTO 16);
END IF;

END IF;
END PROCESS SR16_reg;

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
END rtl;

library ieee;

use ieee.std_logic_1164.all;
--use ieee.numeric_std.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

ENTITY tb_divider48 IS
END tb_divider48;

ARCHITECTURE testbench OF tb_divider48 IS

COMPONENT divider48
PORT( Reset : IN std_logic;
Clk : IN std_logic;
Data2DivBy48 : IN std_logic_vector(12 DOWNTO 0);
Data2DivBy48Valid : IN std_logic;
DataDividedOut : OUT std_logic_vector(12 DOWNTO 0);
);
END COMPONENT;

SIGNAL t_Reset : std_logic;
SIGNAL t_Clk : std_logic;
SIGNAL t_Clkstim : std_logic;
SIGNAL t_Data2DivBy48 : std_logic_vector(12 DOWNTO 0);
SIGNAL t_Data2DivBy48Valid : std_logic;
SIGNAL t_DataDividedOut : std_logic_vector(12 DOWNTO 0);

BEGIN

UUT : divider48
PORT MAP ( Reset => t_Reset,
Clk => t_Clk,
Data2DivBy48 => t_Data2DivBy48,
Data2DivBy48Valid => t_Data2DivBy48Valid,
);

-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
CLOCK_gen: PROCESS
BEGIN
t_Clk <= '1'; WAIT FOR 3.75 ns;
t_Clk <= '0'; WAIT FOR 3.75 ns;
END PROCESS CLOCK_gen;

-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
CLOCKstim_gen: PROCESS
BEGIN
t_Clkstim <= '0'; WAIT FOR 3.75 ns;
t_Clkstim <= '1'; WAIT FOR 3.75 ns;
END PROCESS CLOCKstim_gen;
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
MAIN_gen: PROCESS
BEGIN
t_Data2DivBy48 <= (OTHERS => '0');
t_Data2DivBy48Valid <= '0';
t_Reset <= '1';

FOR i IN 0 TO 13 LOOP
WAIT UNTIL rising_edge(t_Clkstim);
END LOOP;

t_Reset <= '0';

WAIT UNTIL rising_edge(t_Clkstim);
t_Data2DivBy48Valid <= '1';
WAIT UNTIL rising_edge(t_Clkstim);
t_Data2DivBy48Valid <= '0';

FOR i IN 0 TO 170 LOOP
WAIT UNTIL rising_edge(t_Clkstim);
t_Data2DivBy48 <= t_Data2DivBy48 + 48;
t_Data2DivBy48Valid <= '1';
WAIT UNTIL rising_edge(t_Clkstim);
t_Data2DivBy48Valid <= '0';
END LOOP;

WAIT;
END PROCESS MAIN_gen;
-----------------------------------------------------------------------------

END testbench;

Ray Andraka
Guest
Posts: n/a

 11-09-2006
(E-Mail Removed) wrote:
> Mr Andraka,
>
> thank you for your suggestion.
>
>
>>The multiply in this case is a repeating
>>pattern of bits (0x555), which can be done with a tree of adders rather
>>than a multiplier if you do not have full multipliers available.

>
>
> Can you elaborate on your last comment. How would those adders
> be combined ?
>
> Rgds
> André
>

x is input

a= x + x<<2 = x*5
b= a + a<<4 = a*0x11 = x*0x55
y= a+ b<<4 = a + b*0x10 = x*0x555