0

I need to create a 4 bit multiplier as a part of a 4-bit ALU in VHDL code, however the requirement is that we have to use repeated addition, meaning if A is one of the four bit number and B is the other 4 bit number, we would have to add A + A + A..., B number of times. I understand this requires either a for loop or a while loop while also having a temp variable to store the values, but my code just doesn't seem to be working and I just don't really understand how the functionality of it would work.

PR and T are temporary buffer standard logic vectors and A and B are the two input 4 bit numbers and C and D are the output values, but the loop just doesn't seem to work. I don't understand how to loop it so it keeps adding the A bit B number of times and thus do the multiplication of A * B.

WHEN "010" =>
       PR <= "00000000";
       T <= "0000";
       WHILE(T < B)LOOP
       PR <= PR + A;
       T <= T + 1;
       END LOOP;
       C <= PR(3 downto 0);
       D <= PR(7 downto 4); 

2 Answers2

1

This will never work, because when a line with a signal assignment (<=) like this one:

PR <= PR + A;

is executed, the target of the signal assignment (PR in this case) is not updated immediately; instead an event (a future change) is scheduled. When is this event (change) actioned? When all processes have suspended (reached wait statements or end process statements).

So, your loop:

   WHILE(T < B)LOOP
     PR <= PR + A;
     T <= T + 1;
   END LOOP;

just schedules more and more events on PR and T, but these events never get actioned because the process is still executing. There is more information here.


So, what's the solution to your problem? Well, it depends what hardware you are trying to achieve. Are you trying to achieve a block of combinational logic? Or sequential? (where the multiply takes multiple clock cycles)

Matthew Taylor
  • 13,365
  • 3
  • 17
  • 44
  • Thanks for the input, my problem is that I cannot implement a wait statement because the process cannot have both wait statements and a sensitivity list and since this is a part of a larger ALU with a sensitivity list, I am not sure how to loop the repeated addition having the values update immediately. I am not sure what exactly to do because there are some things that I haven't learned yet or hope to teach. – MikeWazowski Nov 27 '19 at 00:00
  • @MikeWazowski You need to decide what hardware you are designing. If this is just part of some combinational logic , then you could use _variables_. They would behave as you your code is expecting the signals to behave. But then why use repeated addition? What not just use the `*` operator? If this is sequential logic, then you've gone about it in completely the wrong way. – Matthew Taylor Nov 27 '19 at 08:37
  • I am trying to understand how to accomplish multiplication instead of converting the types of the a and b to integers or variables and the only way to accomplish this would be to repeatedly add. This hardware is an ALU that accomplishes a certain task, addition of 2 four bits, multiplication of 2 four bits, inverse of 1 four bit, and other tasks based on a select operation as evident by the case statement. The ALU functions are separate meaning that the addition of two bits doesn't affect the output of the other functions, but the input for the ALU functions are all the same. – MikeWazowski Nov 28 '19 at 05:16
  • This is a XY problem. Your real problem is "how can I multiply two 4-bit numbers together?" If you are doing maths, then you should be using the `unsigned` or `signed` types from the `numeric_std` package, as illustrated in another answer here. If `A`, `B` and `PR` are, for example, `unsigned`, ie `signal A, B : unsigned(3 downto 0);` and `signal PR : unsigned(7 downto 0);` then you can just write: `PR <= A * B;`. – Matthew Taylor Nov 28 '19 at 08:11
0

I advise you to try not to think in terms of "temporary variables", "for loops" and "while loops". These are software constructions that can be useful, but ultimately you are designing a piece of hardware. You need to try to think about what physical pieces of hardware can be connected together to achieve your design, then how you might describe them using VHDL. This is difficult at first.

You should provide more information about what exactly you want to achieve (and on what kind of hardware) to increase the probability of getting a good answer.

You don't mention whether your multiplier needs to operate on signed or unsigned inputs. Let's assume signed, because that's a bit harder.

As has been noted, this whole exercise makes little sense if implemented combinationally, so let's assume you want a clocked (sequential) implementation.

You also don't mention how often you expect new inputs to arrive. This makes a big difference in the implementation. I don't think either one is necessarily more difficult to write than the other, but if you expect frequent inputs (e.g. every clock cycle), then you need a pipelined implementation (which uses more hardware). If you expect infrequent inputs (e.g. every 16 or more clock cycles) then a cheaper serial implementation should be used.

Let's assume you want a serial implementation, then I would start somewhere along these lines:

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

entity loopy_mult is
generic(
    g_a_bits    : positive := 4;
    g_b_bits    : positive := 4
);
port(
    clk         : in std_logic;
    srst        : in std_logic;
    -- Input
    in_valid    : in std_logic;
    in_a        : in signed(g_a_bits-1 downto 0);
    in_b        : in signed(g_b_bits-1 downto 0);
    -- Output
    out_valid   : out std_logic;
    out_ab      : out signed(g_a_bits+g_b_bits-1 downto 0)
);
end loopy_mult;

architecture rtl of loopy_mult is

    signal a            : signed(g_a_bits-1 downto 0);
    signal b_sign       : std_logic;

    signal countdown    : unsigned(g_b_bits-1 downto 0);
    signal sum          : signed(g_a_bits+g_b_bits-1 downto 0);
begin

    mult_proc : process(clk)
    begin
        if rising_edge(clk) then
            if srst = '1' then
                out_valid <= '0';
                countdown <= (others => '0');
            else
                if in_valid = '1' then -- (Initialize)
                    -- Record the value of A and sign of B for later
                    a <= in_a;
                    b_sign <= in_b(g_b_bits-1);

                    -- Initialize countdown
                    if in_b(g_b_bits-1) = '0' then
                        -- Input B is positive
                        countdown <= unsigned(in_b);
                    else
                        -- Input B is negative
                        countdown <= unsigned(-in_b);
                    end if;

                    -- Initialize sum
                    sum <= (others => '0');

                    -- Set the output valid flag if we're already finished (B=0)
                    if in_b = 0 then
                        out_valid <= '1';
                    else
                        out_valid <= '0';
                    end if;
                elsif countdown > 0 then -- (Loop)
                    -- Let's assume the target is an FPGA with efficient add/sub
                    if b_sign = '0' then
                        sum <= sum + a;
                    else
                        sum <= sum - a;
                    end if;

                    -- Set the output valid flag when we get to the last loop
                    if countdown = 1 then
                        out_valid <= '1';
                    else
                        out_valid <= '0';
                    end if;

                    -- Decrement countdown
                    countdown <= countdown - 1;
                else
                    -- (Idle)
                    out_valid <= '0';
                end if;
            end if;
        end if;
    end process mult_proc;

    -- Output
    out_ab <= sum;

end rtl;

This is not immensely efficient, but is intended to be relatively easy to read and understand. There are many, many improvements you could make depending on your requirements.

Harry
  • 884
  • 1
  • 8
  • 19