Division with ieee.numeric_std

Discussion in 'VHDL' started by Gabriel Schuster, Sep 21, 2006.

  1. 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;
     
    Gabriel Schuster, Sep 21, 2006
    #1
    1. Advertising

  2. tb_divider.vhdl

    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;
     
    Gabriel Schuster, Sep 21, 2006
    #2
    1. Advertising

  3. tb_alu_div.vhdl

    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;
     
    Gabriel Schuster, Sep 21, 2006
    #3
  4. Gabriel Schuster

    Andy Guest

    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
     
    Andy, Sep 21, 2006
    #4
  5. 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, Sep 22, 2006
    #5
  6. 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
     
    Nicolas Matringe, Sep 22, 2006
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. lezah
    Replies:
    2
    Views:
    7,791
    Mike Treseler
    Feb 6, 2004
  2. Chuck Roth
    Replies:
    3
    Views:
    1,087
    Jim Lewis
    Sep 14, 2005
  3. Weng Tianxiang

    ieee.numeric_std?

    Weng Tianxiang, Feb 11, 2006, in forum: VHDL
    Replies:
    24
    Views:
    8,121
    janeruth
    Jul 23, 2009
  4. JustJohn
    Replies:
    6
    Views:
    663
    JustJohn
    Mar 29, 2006
  5. Chris
    Replies:
    10
    Views:
    1,552
    Chris
    Jun 29, 2007
Loading...

Share This Page