![]() |
|
|
|||||||
![]() |
VHDL - Division with ieee.numeric_std |
|
|
Thread Tools | Search this Thread |
|
|
#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 := 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)), 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 |
|
|
|
|
#2 |
|
Posts: n/a
|
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 := 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, op2_i <= conv_std_logic_vector(j, 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, report "ERROR: DIV - RESA-Assignment" severity failure; assert (resb_o = conv_std_logic_vector(i rem j, 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; |
|
|
|
#3 |
|
Posts: n/a
|
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 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; |
|
|
|
#4 |
|
Posts: n/a
|
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 |
|
|
|
#5 |
|
Posts: n/a
|
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!!! 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 > |
|
|
|
#6 |
|
Posts: n/a
|
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 |
|