J
Jerry Coffin
Guest
Hi All,
I'm one of those software guys, but a couple of weeks ago I bought one
of Xilinx's $99.95 development boards to play with. Though I've seen
hints at the idea that I should be able to write code like 'x <= a
/b;' to do division, when I've tried to synthesize that, I only get
error messages.
Lacking that, I whipped up some code that seems to work, and thought
I'd post it in the hopes that 1) somebody else might find it useful,
and 2) people who know more about VHDL than I do (which is probably
just about everybody) might critique it and offer whatever advice they
think would be helpful/useful/whatever (and although this is my first
post here, I've posted for years on various newsgroups
where...um...robust discusions are normal, so don't worry too much
about hurting my feelings or anything like that...).
Right now, this is hard-coded for 16-bit operands; I haven't yet
looked into
how to parameterize that, but it certainly ought to be pretty simple.
For anybody who's into technicalities, this is a simple radix-2
divider. It
will normally take roughly 2N clock cycles to complete a division,
where N is the difference in size between the (set bits in) the two
operands.
Anyway, on with the code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.numeric_std.ALL;
entity divider is
Port(CLK : in std_Logic;
reset : in std_Logic;
numer : in std_logic_vector(15 downto 0);
denom : in std_logic_vector(15 downto 0);
result : out std_logic_vector(15 downto 0);
remainder: out std_logic_vector(15 downto 0);
done : out std_logic);
end divider;
architecture Behavioral of divider is
constant zero: std_logic_vector(15 downto 0) := "0000000000000000";
constant one : std_logic_vector(16 downto 0) :=
"00000000000000001";
begin
divide : process(clk, numer, denom) is
variable curr_mag : std_logic_vector(16 downto 0);
variable partial : std_Logic_vector(16 downto 0);
-- variable subtrahend : std_logic_vector(15 downto 0);
-- variable magnitude : std_logic_vector(15 downto 0);
variable modulus : std_logic_vector(15 downto 0);
variable res : std_logic_vector(15 downto 0);
type states is (idle, init, lshift, rshift, subs);
variable state : states;
variable difference : std_logic_vector(15 downto 0);
begin
if (CLK = '1' and CLK'event) then
if ( reset = '1') then
state := init;
else
case state is
when init =>
curr_mag := one;
partial(15 downto 0) := denom;
partial(16) := '0';
state := lshift;
when lshift =>
if (numer >= partial) then
partial(16 downto 1) := partial(15 downto 0);
partial(0) := '0';
curr_mag(16 downto 1) := curr_mag(15 downto 0);
curr_mag(0) := '0';
else
state := rshift;
end if;
when rshift =>
-- subtrahend := partial(16 downto 1);
-- magnitude := curr_mag(16 downto 1);
state := subs;
modulus := numer;
res := zero;
when subs =>
-- For more speed at the expense of greater area, use the
commented-out lines.
-- In the case of two sets of two above, just un-comment them. For
those below,
-- un-comment them, and comment-out the simlar lines immediately below
them.
-- The differences in both speed and area are fairly substantial -- at
least
-- with the tools I'm using (Xilinx WebPack ISE) -- I'd be interested
to know
-- whether more expensive tools know how to optimize this sort of
thing
-- automatically.
-- This is another place a better tool might optimize automatically.
My
-- first stab at this bit of code was:
-- if ( modulus >= subtrahend) then
-- modulus := modulus - subtrahend;
-- but that consumes quite a bit more space, basically doing the
subtraction
-- twice.
-- difference := modulus - subtrahend;
difference := modulus - partial(16 downto 1);
if (difference >= 0) then
modulus := difference;
-- res := res or magnitude;
res := res or curr_mag(16 downto 1);
end if;
-- subtrahend(14 downto 0) := subtrahend(15 downto 1);
-- subtrahend(15) := '0';
partial(15 downto 1) := partial(16 downto 2);
partial(16) := '0';
-- magnitude(14 downto 0) := magnitude(15 downto 1);
-- magnitude(15) := '0';
curr_mag(15 downto 1) := curr_mag(16 downto 2);
curr_mag(16) := '0';
-- if ( magnitude = zero) then
if (curr_mag(16 downto 1) = zero) then
remainder <= modulus;
result <= res;
done <= '1';
state := idle;
end if;
when others =>
end case;
end if;
end if;
end process;
end Behavioral;
--
Later,
Jerry.
The universe is a figment of its own imagination.
I'm one of those software guys, but a couple of weeks ago I bought one
of Xilinx's $99.95 development boards to play with. Though I've seen
hints at the idea that I should be able to write code like 'x <= a
/b;' to do division, when I've tried to synthesize that, I only get
error messages.
Lacking that, I whipped up some code that seems to work, and thought
I'd post it in the hopes that 1) somebody else might find it useful,
and 2) people who know more about VHDL than I do (which is probably
just about everybody) might critique it and offer whatever advice they
think would be helpful/useful/whatever (and although this is my first
post here, I've posted for years on various newsgroups
where...um...robust discusions are normal, so don't worry too much
about hurting my feelings or anything like that...).
Right now, this is hard-coded for 16-bit operands; I haven't yet
looked into
how to parameterize that, but it certainly ought to be pretty simple.
For anybody who's into technicalities, this is a simple radix-2
divider. It
will normally take roughly 2N clock cycles to complete a division,
where N is the difference in size between the (set bits in) the two
operands.
Anyway, on with the code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.numeric_std.ALL;
entity divider is
Port(CLK : in std_Logic;
reset : in std_Logic;
numer : in std_logic_vector(15 downto 0);
denom : in std_logic_vector(15 downto 0);
result : out std_logic_vector(15 downto 0);
remainder: out std_logic_vector(15 downto 0);
done : out std_logic);
end divider;
architecture Behavioral of divider is
constant zero: std_logic_vector(15 downto 0) := "0000000000000000";
constant one : std_logic_vector(16 downto 0) :=
"00000000000000001";
begin
divide : process(clk, numer, denom) is
variable curr_mag : std_logic_vector(16 downto 0);
variable partial : std_Logic_vector(16 downto 0);
-- variable subtrahend : std_logic_vector(15 downto 0);
-- variable magnitude : std_logic_vector(15 downto 0);
variable modulus : std_logic_vector(15 downto 0);
variable res : std_logic_vector(15 downto 0);
type states is (idle, init, lshift, rshift, subs);
variable state : states;
variable difference : std_logic_vector(15 downto 0);
begin
if (CLK = '1' and CLK'event) then
if ( reset = '1') then
state := init;
else
case state is
when init =>
curr_mag := one;
partial(15 downto 0) := denom;
partial(16) := '0';
state := lshift;
when lshift =>
if (numer >= partial) then
partial(16 downto 1) := partial(15 downto 0);
partial(0) := '0';
curr_mag(16 downto 1) := curr_mag(15 downto 0);
curr_mag(0) := '0';
else
state := rshift;
end if;
when rshift =>
-- subtrahend := partial(16 downto 1);
-- magnitude := curr_mag(16 downto 1);
state := subs;
modulus := numer;
res := zero;
when subs =>
-- For more speed at the expense of greater area, use the
commented-out lines.
-- In the case of two sets of two above, just un-comment them. For
those below,
-- un-comment them, and comment-out the simlar lines immediately below
them.
-- The differences in both speed and area are fairly substantial -- at
least
-- with the tools I'm using (Xilinx WebPack ISE) -- I'd be interested
to know
-- whether more expensive tools know how to optimize this sort of
thing
-- automatically.
-- This is another place a better tool might optimize automatically.
My
-- first stab at this bit of code was:
-- if ( modulus >= subtrahend) then
-- modulus := modulus - subtrahend;
-- but that consumes quite a bit more space, basically doing the
subtraction
-- twice.
-- difference := modulus - subtrahend;
difference := modulus - partial(16 downto 1);
if (difference >= 0) then
modulus := difference;
-- res := res or magnitude;
res := res or curr_mag(16 downto 1);
end if;
-- subtrahend(14 downto 0) := subtrahend(15 downto 1);
-- subtrahend(15) := '0';
partial(15 downto 1) := partial(16 downto 2);
partial(16) := '0';
-- magnitude(14 downto 0) := magnitude(15 downto 1);
-- magnitude(15) := '0';
curr_mag(15 downto 1) := curr_mag(16 downto 2);
curr_mag(16) := '0';
-- if ( magnitude = zero) then
if (curr_mag(16 downto 1) = zero) then
remainder <= modulus;
result <= res;
done <= '1';
state := idle;
end if;
when others =>
end case;
end if;
end if;
end process;
end Behavioral;
--
Later,
Jerry.
The universe is a figment of its own imagination.