I am trying to do an "add and shift multiplier (sequential)" and I am having problems on the final simulation, the value on the output goes always wrong. I've used a state machine logic to make the control block of the partial sums.
When I make 1 x 1 the output goes wrong (for all products goes wrong) :
This error appears for all multiplicand and multiplier inputs.
I am using the following code to make the sums:
library IEEE;
use IEEE.std_logic_1164.all;
entity adder_8bits is
port (
cin: in STD_LOGIC;
a,b: in STD_LOGIC_VECTOR(7 DOWNTO 0);
s: out STD_LOGIC_VECTOR(8 DOWNTO 0)
);
end adder_8bits;
architecture arch_1 of adder_8bits is
begin
process(a,b,cin)
variable soma:std_logic_vector(8 downto 0);
variable c:std_logic;
begin
c := cin;
for i in 0 to 7 loop
soma(i) := a(i) xor b(i) xor c;
c := (a(i) and b(i)) or ((a(i) xor b(i)) and c);
end loop;
s(7 downto 0) <= soma(7 downto 0);
s(8) <= c;
end process;
end arch_1;
A 8 bit adder to sum the partial results.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity sum_register is
port (
i_DIN : in UNSIGNED(8 DOWNTO 0);
i_LOAD : in STD_LOGIC;
i_CLEAR : in STD_LOGIC;
i_SHIFT : in STD_LOGIC;
i_CLK : in STD_ULOGIC;
o_DOUT : buffer UNSIGNED(15 downto 0)
);
end sum_register;
architecture arch_1 of sum_register is
begin
process(i_CLK)
begin
IF rising_edge(i_CLK) THEN
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 7) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
IF (i_DIN(8) = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
END IF;
END IF;
end process;
end arch_1;
A sum register to get the actual sum value and shift before the other sum.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;
ENTITY controller IS
PORT (
i_CLK : IN STD_ULOGIC;
i_START : IN STD_LOGIC;
i_MLTPLR : IN STD_LOGIC_VECTOR(7 downto 0);
o_MDLD : OUT STD_LOGIC;
o_MRLD : OUT STD_LOGIC;
o_RSLD : OUT STD_LOGIC;
o_RSCLR : OUT STD_LOGIC;
o_RSSHR : OUT STD_LOGIC
);
END controller;
ARCHITECTURE arch_1 OF controller IS
TYPE state_type IS (s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18);
SIGNAL stateT : state_type;
BEGIN
PROCESS(i_CLK)
BEGIN
IF rising_edge(i_CLK) THEN
IF (i_START = '0') THEN
stateT <= s0;
ELSE
CASE stateT IS
when s0 => if (i_START = '1') then
stateT <= s1;
end if;
when s1 => stateT <= s2;
when s2 => if (i_MLTPLR(0) = '1') then
stateT <= s3;
else
stateT <= s4;
end if;
when s3 => stateT <= s4;
when s4 => if (i_MLTPLR(1) = '1') then
stateT <= s5;
else
stateT <= s6;
end if;
when s5 => stateT <= s6;
when s6 => if (i_MLTPLR(2) = '1') then
stateT <= s7;
else
stateT <= s8;
end if;
when s7 => stateT <= s8;
when s8 => if (i_MLTPLR(3) = '1') then
stateT <= s9;
else
stateT <= s10;
end if;
when s9 => stateT <= s10;
when s10 => if (i_MLTPLR(4) = '1') then
stateT <= s11;
else
stateT <= s12;
end if;
when s11 => stateT <= s12;
when s12 => if (i_MLTPLR(5) = '1') then
stateT <= s13;
else
stateT <= s14;
end if;
when s13 => stateT <= s14;
when s14 => if (i_MLTPLR(6) = '1') then
stateT <= s15;
else
stateT <= s16;
end if;
when s15 => stateT <= s16;
when s16 => if (i_MLTPLR(7) = '1') then
stateT <= s17;
else
stateT <= s18;
end if;
when s17 => stateT <= s18;
when s18 => stateT <= s0;
END CASE;
END IF;
END IF;
END PROCESS;
o_MDLD <= '1' when (stateT = s1) else '0';
o_MRLD <= '1' when (stateT = s1) else '0';
o_RSCLR <= '1' when (stateT = s1) else '0';
o_RSLD <= '1' when (stateT = s3 or stateT = s5 or
stateT = s7 or stateT = s9 or
stateT = s11 or stateT = s13 or
stateT = s15 or stateT = s17) else '0';
o_RSSHR <= '1' when (stateT = s4 or stateT = s6 or
stateT = s8 or stateT = s10 or
stateT = s12 or stateT = s14 or
stateT = s16 or stateT = s18) else '0';
END arch_1;
A state machine controller to control the inputs signal from de sum register.
I am using a BDF file to connect all the blocks, the only difference from the schematic below is that in the adder block has a carry in input. The clock of all blocks are in the same pin.
Anyone have any idea what is causing this error?
When implementing your answer:
architecture arch_1 of sum_register is
begin
process(i_CLK)
begin
IF rising_edge(i_CLK) THEN
IF (i_CLEAR = '1') THEN
o_DOUT <= "0000000000000000";
ELSIF (i_LOAD = '1') THEN
o_DOUT(15 downto 8) <= i_DIN;
ELSIF (i_SHIFT = '1') THEN
o_DOUT <= o_DOUT SRL 1;
END IF;
END IF;
end process;
end arch_1;
what happens when you multiply 255 x 255?
Your product is 1 (which would be correct if this were a signed multiply, you specified unsigned multiplier and multiplicand, where the correct answer would be 65025 ("1111111000000001"). Because you have separate load and shift operations you need to save that discarded carry and use it on a shift in. And because you can have successive multiplier bits that are '0' you need to clear that carry after it's used in a shift instruction (defaulting to the expected sign, which is '0' for unsigned multiplies).
You can do that with your original 9 bit path for the adder_8bits sum and saving the carry:
architecture foo of sum_register is
signal carry: std_logic;
begin
process (i_clk)
begin
if rising_edge(i_clk) then
if i_clear = '1' then
o_dout <= (others => '0');
carry <= '0';
elsif i_load = '1' then
o_dout(15 downto 8) <= i_din (7 downto 0);
carry <= i_din(8);
elsif i_shift = '1' then
o_dout <= carry & o_dout(15 downto 1);
carry <= '0'; -- expected sign for multiply result
end if;
end if;
end process;
end architecture;
Note that it's cleared when consumed, requiring a preceding load to interject carry = '1'.
And this contrivance could go away if you have two a load-and-shift load and a load instruction instead of a load instruction and shift instruction. It would require switching from a Moore state machine to a Mealy state machine and reduce the number of states.
You're controller, a Moore state machine can traverse 16 states both shifting and loading for a multiplier of "11111111", a Mealy machine could do that in 8 states with the shift-and-load and shift operations in sum_register.
And the sum_register would look something like:
architecture fum of sum_register is
begin
process (i_clk)
begin
if rising_edge(i_clk) then
if i_clear = '1' then
o_dout <= (others => '0');
elsif i_load_shift = '1' then
o_dout(15 downto 7) <= i_din & o_dout (6 downto 1);
elsif i_shift = '1' then
o_dout <= '0' & o_dout(15 downto 1); -- '0' expected result sign
end if;
end if;
end process;
end architecture;
for a 9 bit sum from adder_8bits. Note the i_load signal is renamed to i_load_shift and controller state machine would need to be re-written as a Mealy machine issuing either i_load_shift = '1' or i_shift = '1' and the other '0' depending on whether the evaluated multiplier bit is a '1' or a '0'.
Note there are plenty of hints here how to signed multiplies even though you declared the multiplier, multiplicand and product as unsigned.