Diseño tonto de sumador en serie con unidad de control

He diseñado un sumador en serie, con una pequeña unidad de control que se supone sincroniza todos los estados ff. Estoy específicamente interesado en la máquina de estado que hace tales cosas (puedes ver un diagrama de bloques aquí . El diseño es el siguiente:

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

entity serial_adder is
generic(num_bits : integer := 4);
port(rst : in std_logic;
      start : in std_logic;
      clk : in std_logic;
      x : in std_logic_vector(num_bits - 1 downto 0);
      y : in std_logic_vector(num_bits - 1 downto 0);
      z : out std_logic_vector(num_bits - 1 downto 0);
      ovf : out std_logic;
      done : out std_logic);
end entity serial_adder;

architecture rtl of serial_adder is
    type states is (s0,s1,s2);
    signal load, ce : std_logic;
    signal x_reg, y_reg, z_reg : unsigned(num_bits - 1 downto 0);
    signal s, next_c, c : std_logic;
    subtype count is natural range 0 to num_bits;
    signal counter : count;
    signal current_state, next_state : states;
begin
    s <= x_reg(0) xor y_reg(0) xor c;
    next_c <= (x_reg(0) and y_reg(0)) xor (x_reg(0) and c) xor (y_reg(0) and c);
    z <= std_logic_vector(z_reg);

    regs_and_ff : process(clk)
    begin
        if load <= '1' then
            x_reg <= unsigned(x);
            y_reg <= unsigned(x);
            z_reg <= to_unsigned(0,num_bits);
            c <= '0';
            counter <= 0;
        elsif ce <= '1' then
            x_reg <= '0' & x_reg(num_bits - 1 downto 1);
            y_reg <= '0' & y_reg(num_bits - 1 downto 1);
            z_reg <= s & z_reg(num_bits - 1 downto 1);
            c <= next_c;
        end if;
    end process regs_and_ff;

    control_unit_out : process(current_state)
    begin
        case current_state is
            when s0 =>
                if start <= '0' then
                    load <= '0'; ce <= '0'; done <= '1';
                    next_state <= s1;
                end if;
            when s1 =>
                ce <= '0';
                if start <= '1' then
                    load <= '1'; done <= '0';
                else
                    load <= '0'; done <= '1';
                end if;
            when s2 =>
                load <= '0';
                done <= '0';
                if counter < num_bits then
                    ce <= '1';
                else 
                    ce <= '0';
                end if;
        end case;
    end process control_unit_out;

    control_unit_sm : process(clk,rst)
    begin
        if rst = '1' then current_state <= s0;
        elsif clk'event and clk = '1' then current_state <= next_state;
        end if;
    end process control_unit_sm;

end architecture rtl;

También he diseñado un banco de pruebas

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

entity tb_serial_adder is
end entity tb_serial_adder;

architecture test of tb_serial_adder is
    signal rst, clk, start, done, ovf : std_logic;
    signal x, y, z : std_logic_vector(3 downto 0);

    component serial_adder is
    generic(num_bits : natural := 4);
    port(rst : in std_logic;
      start : in std_logic;
      clk : in std_logic;
      x : in std_logic_vector(num_bits - 1 downto 0);
      y : in std_logic_vector(num_bits - 1 downto 0);
      z : out std_logic_vector(num_bits - 1 downto 0);
      ovf : out std_logic;
      done : out std_logic);
    end component serial_adder;

    constant clk_period : time := 100 ns;

begin

    DUT : serial_adder
        generic map(num_bits => 4)
        port map(rst => rst,
                    start => start,
                    clk => clk,
                    x => x,
                    y => y,
                    z => z,
                    ovf => ovf,
                    done => done);

    clk_proc : process is
    begin
        clk <= '1';
        wait for clk_period/2;
        clk <= '0';
        wait for clk_period/2;
    end process clk_proc;

    stim_proc : process is
    begin
        x <= "1001";
        y <= "0101";
        rst <= '1';
        start <= '0';
        wait for 200 ns;
        rst <= '0';
        start <= '1';
        wait for 200 ns;
        wait for 1000 ns;
        wait;
    end process stim_proc;


end architecture test;

Sin embargo, no entiendo por qué no funciona. En el siguiente gráfico de los resultados de la simulación:ingrese la descripción de la imagen aquí

Estoy bastante seguro de que el problema es cómo diseñé la máquina de estado, soy nuevo en el diseño de unidades de control. ¿Alguna pista de por qué no funciona?

Gracias

Actualización 1

Siguiendo las sugerencias:

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

entity serial_adder is
generic(num_bits : integer := 4);
port(rst : in std_logic;
    start : in std_logic;
    clk : in std_logic;
    x : in std_logic_vector(num_bits - 1 downto 0);
    y : in std_logic_vector(num_bits - 1 downto 0);
    z : out std_logic_vector(num_bits - 1 downto 0);
    ovf : out std_logic;
    done : out std_logic);
end entity serial_adder;

architecture rtl of serial_adder is
    type states is (s0,s1,s2);
    signal load, ce : std_logic;
    signal x_reg, y_reg, z_reg : unsigned(num_bits - 1 downto 0);
    signal s, next_c, c : std_logic;
    subtype count is natural range 0 to num_bits;
    signal counter : count;
    signal current_state, next_state : states;
begin
    s <= x_reg(0) xor y_reg(0) xor c;
    next_c <= (x_reg(0) and y_reg(0)) xor (x_reg(0) and c) xor (y_reg(0) and c);
    z <= std_logic_vector(z_reg);

    regs_and_ff : process(clk)
    begin
        if clk'event and clk = '1' then
            if load <= '1' then
                x_reg <= unsigned(x);
                y_reg <= unsigned(x);
                z_reg <= to_unsigned(0,num_bits);
                c <= '0';
                counter <= 0;
            elsif ce <= '1' then
                x_reg <= '0' & x_reg(num_bits - 1 downto 1);
                y_reg <= '0' & y_reg(num_bits - 1 downto 1);
                z_reg <= s & z_reg(num_bits - 1 downto 1);
                c <= next_c;
                counter <= counter + 1;
            end if;
        end if;
    end process regs_and_ff;

    control_unit_out : process(current_state)
    begin
    case current_state is
        when s0 =>
            if start = '0' then
                load <= '0'; ce <= '0'; done <= '1';
            else
                next_state <= s1;
            end if;
        when s1 =>
            ce <= '0';
            if start = '1' then
                load <= '1'; done <= '0';
                next_state <= s2;
            else
                load <= '0'; done <= '1';
            end if;
        when s2 =>
            load <= '0';
            done <= '0';
            if counter < num_bits then
                ce <= '1';
            else 
                ce <= '0';
                next_state <= s0;
            end if;
    end case;
    end process control_unit_out;

    control_unit_sm : process(clk,rst)
    begin
        if rst = '1' then current_state <= s0;
        elsif clk'event and clk = '1' then current_state <= next_state;
        end if;
    end process control_unit_sm;

end architecture rtl;

Lamentablemente sigue sin funcionar...

¿Por qué no está mirando las señales de su sumador en serie en la simulación en lugar de solo las señales del banco de pruebas? Parece que eso sería mucho más útil.
¿Te refieres a las señales internas? Puedo publicar una imagen, pero lo que dice es como "no registrado", que no sé qué significa.
Cuando ejecute la simulación, debería poder agregar todas las señales en "serial_adder" a su visor de forma de onda, lo que ayudaría significativamente con la depuración. Pero creo que su problema es que le falta un "si el borde ascendente (clk) entonces" en su proceso "regs_and_ff"
Puedo agregar las "señales internas", pero por alguna razón no puedo visualizarlas.
(Acabo de probar el borde ascendente, todavía no funciona) pero debería haberlo agregado, gracias por eso.
Debería poder agregarlos a la forma de onda. Ya no uso ModelSim y no recuerdo exactamente cómo hacerlo, pero si va a hacer algún trabajo HDL, necesita saber cómo usar las herramientas. Está llegando al estado s1 y luego simplemente sentado allí porque no asigna "next_state"
Acabo de darme cuenta de eso, tratando de arreglarlo.
En Altera Quartus (o Xilinx ISE/Vivado u otra herramienta), asegúrese de mirar el código RTL generado para asegurarse de que todo se haya sintetizado. A veces, las herramientas de síntesis omiten u omiten el código si no coincide exactamente con una plantilla de síntesis conocida. Esta omisión se anotará en el registro de síntesis, pero podría estar oculta dentro de un bosque de advertencias y otros mensajes menos importantes. Si, por ejemplo, un error de diseño de codificación hace que una salida sea siempre 0, todas las puertas detrás de ese 0 constante se eliminan.

Respuestas (1)

En el siguiente proceso, debe agregar una condición comoif clk'event and clk = '1' then

regs_and_ff : process(clk)
begin
    if clk'event and clk = '1' then
        if load = '1' then
            x_reg <= unsigned(x);
            y_reg <= unsigned(x);
            z_reg <= to_unsigned(0,num_bits);
            c <= '0';
            counter <= 0;
        elsif ce = '1' then
            x_reg <= '0' & x_reg(num_bits - 1 downto 1);
            y_reg <= '0' & y_reg(num_bits - 1 downto 1);
            z_reg <= s & z_reg(num_bits - 1 downto 1);
            c <= next_c;
        end if;
    end if;
end process regs_and_ff;

Encontré algunos de los siguientes errores en su proceso FSM:

control_unit_out : process(current_state, start, counter) --here in sensitivity list you should add all signals which will use in any comparison (if/elsif/else, case and etc. structures)
begin
    case current_state is
        when s0 =>
            if start = '0' then --here you used incorrect sign for comparison
                load <= '0'; ce <= '0'; done <= '1';
                next_state <= s1;
            end if;
        when s1 => -- in this state you didn't assign next_state so your FSM stop in this state
            ce <= '0';
            if start = '1' then --here you used incorrect sign for comparison
                load <= '1'; done <= '0';
            else
                load <= '0'; done <= '1';
            end if;
        when s2 => --you also should add condition to achieve a next_state in this state too (like in prev)
            load <= '0';
            done <= '0';
            if counter < num_bits then
                ce <= '1';
            else 
                ce <= '0';
            end if;
    end case;
end process control_unit_out;

También tiene un reinicio del contador counter <= 0;pero nunca lo cuenta ni lo incrementa, creo que debería agregarlo en su lógica si desea que la comparación en el S2estado funcione correctamenteif counter < num_bits then

Intente corregir los errores y creo que su módulo funcionará. Todos los errores que anoté en los comentarios a una línea específica en el código.
Se corrigieron algunos errores, pero no conozco la lógica de su FSM, así que hágalo usted mismo.

Actualización 1: este código funciona, pero no creo que la lógica sea correcta, por lo que debe resolverlo usted mismo

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

entity serial_adder is
generic(num_bits : integer := 4);
port(
    rst   :  in std_logic;
    start :  in std_logic;
    clk   :  in std_logic;
    x     :  in std_logic_vector(num_bits - 1 downto 0);
    y     :  in std_logic_vector(num_bits - 1 downto 0);
    z     : out std_logic_vector(num_bits - 1 downto 0);
    ovf   : out std_logic;
    done  : out std_logic);
end entity serial_adder;

architecture rtl of serial_adder is
    type states is (s0,s1,s2);
    signal load, ce : std_logic;
    signal x_reg, y_reg, z_reg : unsigned(num_bits - 1 downto 0);
    signal s, next_c, c : std_logic;
    subtype count is natural range 0 to num_bits;
    signal counter : count;
    signal current_state, next_state : states;
begin
    s <= x_reg(0) xor y_reg(0) xor c;
    next_c <= (x_reg(0) and y_reg(0)) xor (x_reg(0) and c) xor (y_reg(0) and c);
    z <= std_logic_vector(z_reg);

    regs_and_ff : process(clk)
    begin
        if clk'event and clk = '1' then
            if load = '1' then -- here was mistake ('<=' instead '=')
                x_reg <= unsigned(x);
                y_reg <= unsigned(x);
                z_reg <= to_unsigned(0,num_bits);
                c <= '0';
                counter <= 0;
            elsif ce = '1' then -- here was mistake ('<=' instead '=')
                x_reg <= '0' & x_reg(num_bits - 1 downto 1);
                y_reg <= '0' & y_reg(num_bits - 1 downto 1);
                z_reg <= s & z_reg(num_bits - 1 downto 1);
                c <= next_c;
                counter <= counter + 1;
            end if;
        end if;
    end process regs_and_ff;

    control_unit_out : process(current_state, start, counter)
    begin
        case current_state is
            when s0 =>
                if start = '0' then
                    load <= '0'; ce <= '0'; done <= '1';
                    next_state <= s0; -- I added this line to avoid latch implementation. 
                    --You can change the next_state value in for this condition as you need
                else
                    next_state <= s1;
                end if;
            when s1 =>
                ce <= '0';
                if start = '1' then
                    load <= '1'; done <= '0';
                    next_state <= s2;
                else
                    load <= '0'; done <= '1';
                    next_state <= s1; -- I added this line to avoid latch implementation. 
                    --You can change the next_state value in for this condition as you need
                end if;
            when s2 =>
                load <= '0';
                done <= '0';
                if counter < num_bits then
                    ce <= '1';
                    next_state <= s2; -- I added this line to avoid latch implementation. 
                    --You can change the next_state value in for this condition as you need
                else 
                    ce <= '0';
                    next_state <= s0;
                end if;
        end case;
    end process control_unit_out;

    control_unit_sm : process(clk,rst)
    begin
        if rst = '1' then current_state <= s0;
        elsif clk'event and clk = '1' then current_state <= next_state;
        end if;
    end process control_unit_sm;

end architecture rtl;

A continuación puede encontrar la forma de onda de mi simulación del código tomado arriba.forma de onda

Actualicé mi código usando sus sugerencias, todavía no funciona. Verificaré si la lógica de la máquina de estado está bien.
Tal vez lo he solucionado, parte del problema era lo que dijiste. Sin embargo, me pregunto si podría simplificar las máquinas de estado para este diseño específico.
Actualicé mi respuesta. Si tiene preguntas, siéntase libre de preguntar. Pensaré en tu FSM, pero no parece tan complicado
Esta es la primera vez que diseño una unidad sincronizada usando una máquina de estado, lo cual es realmente confuso para mí.
Deberías usar rising_edge(clk)en lugar declk'event and clk = '1'
@scary_jeff no tiene que hacerlo. rising_edge(clk)y clk'event and clk = '1'lo mismo en este caso
rising_edge()y falling_edge()hacer frente a todos los bordes válidos, el 'eventestilo no lo hace. ¡ El 'eventestilo incluso considera una 'X'transición '1'como un borde! ¿Por qué no aprovechar las construcciones de lenguaje simples diseñadas para ayudarlo?