Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
12 years ago

Weird VHDL Multiplier Problem

Hello all,

I was recently given reign over a DE0-Nano board by my research adviser to turn into a interference fringe counter of sorts but I am having some problems programming multiplication in VHDL and cannot seem to find anyone with similar errors online (my adviser also seems to be befuddled as to what, exactly, is wrong). I am trying to multiply two 32 bit unsigned numbers, one of which is a constant and the other a signal from a button press(for testing purposes), and then later convert it to bcd and put it on a 7-seg display. I have successfully implemented a binary to bcd and bcd to 7seg display code and use a set of seven segmented displays to check the outputs for my multiplier. For certain constant values, such as "100...0" or "111...1" or "100...01", the multiplier seems to work properly. However, if the multiplier tries to multiply a 'sandwiched' zero (like the number 13 which has the binary representation 1101), it will fail to produce the correct output. For example if the constant is 13, the display reads the following solutions for each multiplication: 0x13=0; 1x13=13; 2x13=54; 3x13=39; 4x13=76; 5x13=65; etc... As you can see, some of the values are correct, however others are plain wrong. (NOTE: the pattern for 13 seems typical... the even multiples are off, although I do not know for sure if this is always the case).

Here's my code for the multiplier:


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mult_32 is
port (
  a: in  unsigned(31 downto 0);
  c   : out unsigned(63 downto 0);
  clear : in std_logic
);
constant b: unsigned(31 downto 0):=to_unsigned(13,32); 
end entity mult_32;
architecture rtl of mult_32 is
signal a_reg : unsigned(31 downto 0);
signal b_reg: unsigned(31 downto 0);
signal c_reg : unsigned(63 downto 0);
begin
    process (clear)
    begin
        if (clear ='1') then
            -- Reset all register data to 0
            a_reg <= (others => '0');
            b_reg <= (others => '0');
            c_reg <= (others => '0');
        else
            -- Store input and output values in registers
            a_reg <= a;
            b_reg <= b;
            c_reg <= a_reg * b_reg;    
        end if;
    end process;
    
c<=c_reg;
end rtl;

I am new to coding in VHDL and believe that I have likely made some sort of syntax error, type cast conversion error (although I have been careful to use unsigned for everything) or other newbie mistake. If it is relevant, I am writing and compiling my code in Quratus II version 13 (64 bit version).

Thanks for your help.

12 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    if I wire it up to the button press or use an input signal from a function generator it produces the correct values.

    --- Quote End ---

    As a general rule for FPGA design; whenever you "look" at an external signal in the synchronous domain of the FPGA, you should always synchronize external signals to the FPGA clock domain.

    In the case of your push-button, this generally means using a dual-DFF synchronizer, followed by debounce logic, eg., the signal state must be static for 100 clocks before the output of the debounce logic outputs a change in state.

    In the case of your external synthesizer, if there are no reflections on the signal, using a dual-DFF synchronizer should be fine.

    You can use the SignalTap II logic analyzer to "capture" a trace from your external signal, eg., at 50MHz or 100MHz sample rate, and from those traces, you will see the effect of button bounce.

    Cheers,

    Dave
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    One last question for you guys, although this technically isn't a multiplier question (but I'm trying to implement it inside the multiplier so I guess it is related). I added a line of code after the multiplication to do division (as well as the necessary registers).

    c_reg is the numerator and b_reg is the denominator in this code. e_reg stores the value for the division. I checked both of these registers to make sure they are the correct values (and they indeed are for any given inputs from a function generator).

    Now the code that does the computation looks like this:

    begin
    	process (clk, clear, disp)
    	begin
    		if (clear ='1') then
    			-- Reset all register data to 0
    			a_reg <= (others => '0');
    			b_reg <= (others => '0');
    			c_reg <= (others => '0');
    			d_reg <= (others => '0');
    			e_reg <= (others => '0');
    		elsif rising_edge(clk) then
    			-- Store input and output values in registers
    			a_reg <= a;
    			b_reg <= b;
    			d_reg <= d;
    			c_reg <= (a_reg * d_reg);
    			e_reg <= (c_reg/b_reg);
    		end if;
    	end process;

    The blue line is what I added. Now when I go to have the data display on the display I made, it doesn't output the right values (although its always within 10% of the correct value, which is odd to me).

    For completeness, I tried writing a separate 'divide.vhd' file for division but had a similar problem and thought that it may be caused by some kind of clock issue between the multiplier and divider (although I wouldn't know why) and thought if it was imbedded in the multiplication file it would possibly correct the issue in compilation. However, that does not seem to be the case.

    Thanks for your help,

    Nathan