Division with ieee.numeric_std

G

Gabriel Schuster

Guest
Hi everybody,

I've got a little problem with the division module (part of a
microcontroller alu) in my current project: I found a nice code sample
in the www implementing a similar module.
Originally ieee.std_logic_arith was used to create it, which I strictly
avoid in my project so I rewrote the divider module using
ieee.numeric_std... but unfortunately it doesn't work so far.

I think there's something wrong in the assignments / conversion between
std_logic_vector and unsigned. I'd appreciate any help, because I'm used
to work with std_logic_arith and I think I'll have more of these
conversion problems in the near future.
How is this conversion done the right way???

Here are the sources of the two divider modules. I also got two
testbenches, which I can add.

Thanks
Gabriel

=====================WORKING=========================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity divider is

generic (DWIDTH : integer := 8);

port (dvdnd_i : in std_logic_vector(DWIDTH-1 downto 0); -- Dividend
dvsor_i : in std_logic_vector(DWIDTH-1 downto 0); -- Divisor
qutnt_o : out std_logic_vector(DWIDTH-1 downto 0); --
Quotient
rmndr_o : out std_logic_vector(DWIDTH-1 downto 0);
ov_o : out std_logic); -- Remainder

end divider;

architecture rtl of divider is
begin -- rtl

ov_o <= '1' when dvsor_i = "00000000" else '0';

-- purpose: Divide dvdnd_i through dvsor_i and deliver the result to
qutnt_o
-- and the remainder to rmndr_o.
-- type : combinational
-- inputs : dvdnd_i, dvsor_i
-- outputs: qutnt_o, rmndr_o
p_divide: process (dvdnd_i, dvsor_i)

variable v_actl_dvdnd : unsigned(DWIDTH-1 downto 0);
variable v_dffrnc : unsigned(DWIDTH-1 downto 0);
variable v_qutnt : unsigned(DWIDTH-1 downto 0);

begin -- process p_divide

v_actl_dvdnd := unsigned(dvdnd_i);

for i in DWIDTH-1 downto 0 loop
-- If the divisor can be subtracted from this part of the
dividend, then
-- the corresponding bit of the quotient has to be 1, otherwise 0.
if conv_std_logic_vector(v_actl_dvdnd(DWIDTH-1 downto i),DWIDTH) >=
dvsor_i then
-- Divisor can be subtracted
v_qutnt(i) := '1';
v_dffrnc := conv_unsigned(v_actl_dvdnd(DWIDTH-1 downto i),DWIDTH)
- unsigned(dvsor_i);
-- As long as this is not the last step of calculation, shift the
-- intermediate result.
if i /= 0 then
v_actl_dvdnd(DWIDTH-1 downto i) := v_dffrnc(DWIDTH-1-i downto 0);
v_actl_dvdnd(i-1) := dvdnd_i(i-1);
end if;
else
-- Divisor is greater than this part of the dividend.
v_qutnt(i) := '0';
v_dffrnc := conv_unsigned(v_actl_dvdnd(DWIDTH-1 downto i),DWIDTH);
end if;
end loop; -- i

rmndr_o <= std_logic_vector(v_dffrnc);
qutnt_o <= std_logic_vector(v_qutnt);

end process p_divide;

end rtl;


=============================NOT WORKING=============================
-- remark:
-- this is the numeric_std version
-- it's possible to simulate the other one with ghdl using --ieee=synopsis
-- but several people suggested to switch to the "real" ieee-stuff
--

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

entity alu_div is
port (
op1_i : in std_logic_vector(7 downto 0); -- dividend
op2_i : in std_logic_vector(7 downto 0); -- divisor
resa_o : out std_logic_vector(7 downto 0); -- result
resb_o : out std_logic_vector(7 downto 0); -- remainder
ov_o : out std_logic
);
end alu_div;

architecture rtl of alu_div is
begin

ov_o <= '1' when (op2_i="00000000") else '0';

p_divide: process (op1_i,op2_i)
variable v_result : unsigned(7 downto 0);
variable v_remainder : unsigned(7 downto 0);
variable v_tmp : unsigned(7 downto 0);
begin
v_tmp := unsigned(op1_i);
for i in 7 downto 0 loop
if (std_logic_vector(v_tmp(7 downto i)) >= op2_i) then
v_result(i) := '1';
v_remainder := unsigned(v_tmp(7 downto i)) - unsigned(op2_i);
if (i /= 0) then
v_tmp(7 downto i) := v_remainder(7-i downto 0);
v_tmp(i-1) := op1_i(i-1);
end if;
else
v_result(i) := '0';
v_remainder := "00000000";
v_remainder(7-i downto 0) := unsigned(v_tmp(7 downto i));
--v_remainder := to_unsigned(to_integer(v_tmp(7 downto i)),8);
end if;
end loop; -- i

resa_o <= std_logic_vector(v_result);
resb_o <= std_logic_vector(v_remainder);

end process p_divide;

end rtl;
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
library std;
use std.textio.all;


entity tb_divider is
generic (DWIDTH : integer := 8);
end tb_divider;

architecture behave of tb_divider is

function printb (bv : in std_logic_vector) return string is
alias bv_norm : std_logic_vector(1 to bv'length) is bv;
variable result : string(1 to bv'length);
begin
for index in bv_norm'range loop
if bv_norm(index) = '0' then
result(index) := '0';
else
result(index) := '1';
end if;
end loop;
return result;
end printb;

component divider
port (dvdnd_i : in std_logic_vector(DWIDTH-1 downto 0); -- Dividend
dvsor_i : in std_logic_vector(DWIDTH-1 downto 0); -- Divisor
qutnt_o : out std_logic_vector(DWIDTH-1 downto 0); --
Quotient
rmndr_o : out std_logic_vector(DWIDTH-1 downto 0);
ov_o : out std_logic); -- Remainder
end component divider;

signal op1_i : std_logic_vector(7 downto 0) := "00000000";
signal op2_i : std_logic_vector(7 downto 0) := "00000000";
signal resa_o : std_logic_vector(7 downto 0);
signal resb_o : std_logic_vector(7 downto 0);
signal ov_o : std_logic;

begin

uut: divider
port map (
dvdnd_i => op1_i,
dvsor_i => op2_i,
qutnt_o => resa_o,
rmndr_o => resb_o,
ov_o => ov_o
);

p_testbench: process
variable l : line;
begin
for i in 0 to 255 loop
for j in 0 to 255 loop
op1_i <= conv_std_logic_vector(i,8);
op2_i <= conv_std_logic_vector(j,8);
wait for 10 ns;
write(l,string'("OP1 :"));
write(l,printb(op1_i));
write(l,string'(" / OP2 :"));
write(l,printb(op2_i));
writeline(output,l);
write(l,string'("RESA:"));
write(l,printb(resa_o));
write(l,string'(" / RESB:"));
write(l,printb(resb_o));
write(l,string'(" / OV:"));
if (ov_o = '1') then
write(l,string'("1"));
else
write(l,string'("0"));
end if;
writeline(output,l);
if (op2_i = "00000000") then
assert (ov_o = '1')
report "ERROR: DIV BY Zero - OV-Assignment"
severity failure;
else
assert (ov_o = '0')
report "ERROR: DIV - OV-Assignment"
severity failure;
assert (resa_o = conv_std_logic_vector(i/j,8))
report "ERROR: DIV - RESA-Assignment"
severity failure;
assert (resb_o = conv_std_logic_vector(i rem j,8))
report "ERROR: DIV - RESB-Assignment"
severity failure;
end if;
end loop;
end loop;
assert false
report "Simulation successfully finished."
severity note;
wait;
end process p_testbench;

end behave;
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library std;
use std.textio.all;


entity tb_alu_div is
end tb_alu_div;

architecture behave of tb_alu_div is

function printb (bv : in std_logic_vector) return string is
alias bv_norm : std_logic_vector(1 to bv'length) is bv;
variable result : string(1 to bv'length);
begin
for index in bv_norm'range loop
if bv_norm(index) = '0' then
result(index) := '0';
else
result(index) := '1';
end if;
end loop;
return result;
end printb;

component alu_div
port (
op1_i : in std_logic_vector(7 downto 0); -- dividend
op2_i : in std_logic_vector(7 downto 0); -- divisor
resa_o : out std_logic_vector(7 downto 0); -- result
resb_o : out std_logic_vector(7 downto 0); -- remainder
ov_o : out std_logic
);
end component alu_div;

signal op1_i : std_logic_vector(7 downto 0) := "00000000";
signal op2_i : std_logic_vector(7 downto 0) := "00000000";
signal resa_o : std_logic_vector(7 downto 0);
signal resb_o : std_logic_vector(7 downto 0);
signal ov_o : std_logic;

begin

uut: alu_div
port map (
op1_i => op1_i,
op2_i => op2_i,
resa_o => resa_o,
resb_o => resb_o,
ov_o => ov_o
);

p_testbench: process
variable l : line;
variable v_16 : unsigned(15 downto 0);
begin
v_16 := "0000000000000000";
for i in 0 to 65535 loop
op1_i <= std_logic_vector(v_16(15 downto 8));
op2_i <= std_logic_vector(v_16(7 downto 0));
wait for 10 ns;
write(l,string'("OP1 :"));
write(l,printb(op1_i));
write(l,string'(" / OP2 :"));
write(l,printb(op2_i));
writeline(output,l);
write(l,string'("RESA:"));
write(l,printb(resa_o));
write(l,string'(" / RESB:"));
write(l,printb(resb_o));
write(l,string'(" / OV:"));
if (ov_o = '1') then
write(l,string'("1"));
else
write(l,string'("0"));
end if;
writeline(output,l);
if (op2_i = "00000000") then
assert (ov_o = '1')
report "ERROR: DIV BY Zero - OV-Assignment"
severity failure;
else
assert (ov_o = '0')
report "ERROR: DIV - OV-Assignment"
severity failure;
assert (resa_o = std_logic_vector(unsigned(op1_i) /
unsigned(op2_i)))
report "ERROR: DIV - RESA-Assignment"
severity failure;
assert (resb_o = std_logic_vector(unsigned(op1_i) rem
unsigned(op2_i)))
report "ERROR: DIV - RESB-Assignment"
severity failure;
end if;
v_16 := v_16 + 1;
end loop;
assert false
report "Simulation successfully finished."
severity note;
wait;
end process p_testbench;

end behave;
 
The following statement probably does not do what you want:

if (std_logic_vector(v_tmp(7 downto i)) >= op2_i) then

What you have is a comparison of two slvs, which iirc, is based on
length, not value(?).

You should convert op2_i to unsigned, and maybe have to resize() on
v_tmp, but you do not want to convert it to slv!

Be careful what you ask for, because the compiler will give you exactly
that!

Andy
 
Thanks a lot!!!
I've changed it to

if (to_integer(v_tmp(7 downto i)) >= to_integer(unsigned(op2_i))) then

and it works perfectly!!! :D

Andy wrote:
The following statement probably does not do what you want:

if (std_logic_vector(v_tmp(7 downto i)) >= op2_i) then

What you have is a comparison of two slvs, which iirc, is based on
length, not value(?).

You should convert op2_i to unsigned, and maybe have to resize() on
v_tmp, but you do not want to convert it to slv!

Be careful what you ask for, because the compiler will give you exactly
that!

Andy
 
Gabriel Schuster a écrit :
Thanks a lot!!!
I've changed it to

if (to_integer(v_tmp(7 downto i)) >= to_integer(unsigned(op2_i))) then
You can drop the conversions
if (v_tmp(7 downto i) >= unsigned(op2_i)) then

Nicolas
 

Welcome to EDABoard.com

Sponsor

Back
Top