First post, etc.

J

Jerry Coffin

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;
 
P

Paul Uiterlinden

Jerry said:
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...).


Just a few personal observations:

1) In stead of using "if clk = '1' and clk'event" (by the way: the
paranthesis are not needed, this is not C ;-) ), I'd rather write
"wait until clk = '1'" or "wait until rising_edge(clk)". I just do not
like "if .. end if" statements spanning a lot of lines if that is not
needed.

2) For the same reason I would put the reset part at the end of the process:

if ( reset = '1') then
state := init;
end if;

3) In stead of writing:

partial(16 downto 1) := partial(15 downto 0);
partial(0) := '0';

you could write this in a single line:

partial := partial(15 downto 0) & '0';

For the rest: for a software guy your code looks pretty good to me! ;-)
I did not look at the algorithm is self.

One thing though: I don't see signal "done" being set to '0' anywhere. I
suppose this should be done in state init.

OK, another thing: I see that state init is left unconditionally.
Shouldn't there be some kind of request signal?

Yikes, another thing! Do not use std_logic_arith and std_logic_unsigned
(and certainly not both at the same time). Use numeric_std instead. It
is standardized properly, the other two are not.

Now that I said this, I now see that you use "if difference >=0 then".
By using std_logic_unsigned this is false only for value zero. I guess
you should have used package std_logic_signed instead. But again: rather
use package numeric_std and delcare difference to be of type signed(15
downto 0).

Paul.
 
P

Paul Uiterlinden

Paul said:
Now that I said this, I now see that you use "if difference >=0 then".
By using std_logic_unsigned this is false only for value zero.

Errr, always true, for any value. An unsigned is >= 0 per definition.

Paul.
 
J

Jerry Coffin

[ ... ]
1) In stead of using "if clk = '1' and clk'event" (by the way: the
paranthesis are not needed, this is not C ;-) ), I'd rather write
"wait until clk = '1'" or "wait until rising_edge(clk)". I just do not
like "if .. end if" statements spanning a lot of lines if that is not
needed.

I tried that, but apparently other things need to change as well to
make that work -- when I try this by itself, I get an error message
saying I can't have both a wait statement and signal sensitivity
specified as part of the process declaration. I haven't tried to
eliminate the latter to see exactly what else would need to change if
I did that though...
2) For the same reason I would put the reset part at the end of the process:

if ( reset = '1') then
state := init;
end if;

Seems reasonable.
3) In stead of writing:

partial(16 downto 1) := partial(15 downto 0);
partial(0) := '0';

you could write this in a single line:

partial := partial(15 downto 0) & '0';

Ah, thank you. Undoubtedly the books I have mention that somewhere,
but if so I haven't run across it yet (though I have a tendency read
more or less randomly rather than working through them sequentially,
so I shouldn't be surprised at missing a few things).
One thing though: I don't see signal "done" being set to '0' anywhere. I
suppose this should be done in state init.

Oops, you're quite right.
OK, another thing: I see that state init is left unconditionally.
Shouldn't there be some kind of request signal?

Maybe -- I had written it with a "start" signal, but basically it
ended up as simply the complement of the reset signal.

Another possibility would be to eliminate the init state entirely, and
just carry out all the 'init' actions directly in response to the
reset signal. At the moment, I left it as part of the state machine
proper, but I'm honestly not sure how much real difference that makes.
Yikes, another thing! Do not use std_logic_arith and std_logic_unsigned
(and certainly not both at the same time). Use numeric_std instead. It
is standardized properly, the other two are not.

Now that I said this, I now see that you use "if difference >=0 then".
By using std_logic_unsigned this is false only for value zero. I guess
you should have used package std_logic_signed instead. But again: rather
use package numeric_std and delcare difference to be of type signed(15
downto 0).

Hmm....I may have to spend a bit more time in the books to entirely
understand this -- I'd assumed that comparisons on a particular type
would always be done the same way, and that including the other
packages would simply add other types with operators to work on them.

Thanks for your comments -- some for their direct content and
(particularly) the last for pointing out an area I clearly need to
study more closely.
 
R

rickman

Jerry said:
[ ... ]
1) In stead of using "if clk = '1' and clk'event" (by the way: the
paranthesis are not needed, this is not C ;-) ), I'd rather write
"wait until clk = '1'" or "wait until rising_edge(clk)". I just do not
like "if .. end if" statements spanning a lot of lines if that is not
needed.

I tried that, but apparently other things need to change as well to
make that work -- when I try this by itself, I get an error message
saying I can't have both a wait statement and signal sensitivity
specified as part of the process declaration. I haven't tried to
eliminate the latter to see exactly what else would need to change if
I did that though...

Yes, you can't have both. If you use a wait, you remove the sensitivity
list. But I don't recommend that. The if rising_edge(clk) is a
standard form that nearly all synthesis will recognize while not all
tools recognize a wait.

Also, you only need the clock in your sensitivity list. None of the
other signals are capable of affecting the state of the output other
than when clock changes. So you don't need any other signals in the
list.
Seems reasonable.

Funny, I am a hardware designer who has has some training in software.
I was taught (and still prefer) to put the short conditions ahead of the
long ones since it is much easier to read over them. I always put the
short reset in front of the rest.

Hmm....I may have to spend a bit more time in the books to entirely
understand this -- I'd assumed that comparisons on a particular type
would always be done the same way, and that including the other
packages would simply add other types with operators to work on them.

Thanks for your comments -- some for their direct content and
(particularly) the last for pointing out an area I clearly need to
study more closely.

The type std_logic_vector as defined in the ieee standard, does not have
comparison operators other than '='. In order to use the other
comparisons, you need to either use one of the ...signed/...unsigned
libraries which is not recommended, or use numeric_std and make the
signal a signed or unsigned type. Then the operator is defined.

--

Rick "rickman" Collins

(e-mail address removed)
Ignore the reply address. To email me use the above address with the XY
removed.

Arius - A Signal Processing Solutions Company
Specializing in DSP and FPGA design URL http://www.arius.com
4 King Ave 301-682-7772 Voice
Frederick, MD 21701-3110 301-682-7666 FAX
 
P

Paul Uiterlinden

rickman said:
Yes, you can't have both. If you use a wait, you remove the sensitivity
list. But I don't recommend that. The if rising_edge(clk) is a
standard form that nearly all synthesis will recognize while not all
tools recognize a wait.

Really? Surely tools do recognize "wait until clk = '1'" as the first
statement in a process? If they do not, I would not care to use those tools!
Funny, I am a hardware designer who has has some training in software.
I was taught (and still prefer) to put the short conditions ahead of the
long ones since it is much easier to read over them. I always put the
short reset in front of the rest.

And I usually put the normal operation of the code first, followed by
the other stuff such as reset. There's something to be said for both
strategies. :)

Paul.
 
P

Paul Uiterlinden

A

Alan Fitch

The type std_logic_vector as defined in the ieee standard, does not have
comparison operators other than '='. In order to use the other
comparisons, you need to either use one of the ...signed/...unsigned
libraries which is not recommended, or use numeric_std and make the
signal a signed or unsigned type. Then the operator is defined.

Hi Rick, sorry to be pedantic :), but enumerated types (such as
std_logic)
do have implicit comparison operators defined. They are defined such
that
the value that occurs to the right in the type declaration is greater
than a value that occurs left of it.

Thus '1' is > '0'.

For comparison of vectors (such as std_logic_vector), the comparison
operator will do comparison using this ordering from left to right
of the array. However if the arrays are different sizes, "funny
things"
will happen.

So

a) if your arrays are the same length
b) you "think" of the contents as unsigned numbers
c) the vectors only contain '0' and '1'

the relational operators will work, and synthesise correctly.

However if you "think" of the contents as signed, or the lengths
are different, or you've got e.g. 'L' mixed with '0', horrible
(but well-defined) things will happen.

Having said that, I am just being pedantic - of course you should
use an arithmetic package, preferably numeric_std.

Regarding another comment (by someone I've snipped out) about the
use of both std_logic_arith and std_logic_unsigned, this is often
necessary as certain functions that you want to have when using
std_logic_signed or std_logic_unsigned are only available in
std_logic_arith - another good reason for preferring numeric_std,
which has a cleaner design,

regards
Alan

--
Alan Fitch
Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * Perl * Tcl/Tk * Verification * Project
Services

Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, Hampshire, BH24
1AW, UK
Tel: +44 (0)1425 471223 mail:
(e-mail address removed)
Fax: +44 (0)1425 471573 Web:
http://www.doulos.com

The contents of this message may contain personal views which are not
the
views of Doulos Ltd., unless specifically stated.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top