我的 VDHL 代码运行不正确 - vhdl 中的平方根

My VDHL code runs incorrectly - square root in vhdl

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

entity RaccinCarreSequentielle is

generic(    
    N: natural:= 16
    );
port(
    X: unsigned(2*N-1 downto 0);
    reset : in std_logic; --clear signal
    clk : in std_logic;
    state_done :  in std_logic; --start
    result_done : out std_logic;
    result :      out unsigned(2*N-1 downto 0)
    );
end entity;

architecture state_machine_raccincarre_arc of RaccinCarreSequentielle is
    type state is (s0_wait,s1_init,s2_calcul,s3_fini);
    signal pre_state,next_state: state;
begin
    state_register:process(reset,clk)
    begin
        if reset = '1' then
            pre_state <= s0_wait;
        elsif rising_edge(clk) then
            pre_state <= next_state;
        end if;
    end process state_register;

state_machine: process(pre_state,state_done)
    variable rx,rz,rv : unsigned(2*N-1 downto 0);
    variable ri: unsigned(N-1 downto 0);
begin
    case pre_state is
        when s0_wait =>
            if state_done = '1' then
                next_state <= s1_init;
            else 
                next_state <= s0_wait;
            end if;
        when s1_init => 
            next_state <= s2_calcul;
            rx := x;
            rz := (others => '0');
            rv := (2*N-2 => '1', others => '0');
            ri := to_unsigned(N-1,N);
        when s2_calcul =>
            if ri > 0 then
                    ri := ri - 1;
                    rz := rz + rv;
                    if rx > rz then
                         rx := rx - rz;
                         rz := rz + rv;
                    else 
                         rz := rz - rv;
                    end if;
                    rz := '0' & rz(2*N-1 downto 1);
                    rv := "00" & rv(2*N-1 downto 2);
                    next_state <= s2_calcul;
                 else
                    next_state <= s3_fini;
            end if;
        when s3_fini =>
            result <= rz;           
            if state_done = '0' then
                next_state <= s0_wait;
            else 
                next_state <= s3_fini;
            end if;
        when others =>
            null;
    end case;
end process state_machine;
                
result_proc: process(pre_state)
begin
    if pre_state = s3_fini then
        result_done <= '1';
    else 
        result_done <= '0';
    end if;
end process result_proc;
end architecture; 

当我在 state2 中使用 for 循环时,我的代码将 运行 正确并且我的结果很好。例如,当我想求 255 的平方根时,我会得到 15。但是当我不想在 state2_calcul 中使用 For 循环时,如您所见。所以我每次进入 state2 时都做了一个 if 语句来减少变量 RI,如下所示。我做了一个模拟,但是状态总是停在状态2,它不能像我的link。

when s2_calcul =>
    if ri > 0 then
            ri := ri - 1;
            rz := rz + rv;
            if rx > rz then
                 rx := rx - rz;
                 rz := rz + rv;
            else 
                 rz := rz - rv;
            end if;
            rz := '0' & rz(2*N-1 downto 1);
            rv := "00" & rv(2*N-1 downto 2);
            next_state <= s2_calcul;
         else
            next_state <= s3_fini;
    end if;

我认为问题出在嵌套 IF 上,但是当我更改它时,没有任何变化。有人可以帮我解释这个问题,我该如何解决。谢谢

你无法记住设计的组合部分中的任何内容。所以你需要 rirxrvrz 的寄存器。这些寄存器在某种程度上是你的全局状态的一部分,它确实是它们的组合,也是 pre_state 寄存器的一部分。

让我们继续您已经使用的样式:一个用于寄存器的同步过程,另一个用于组合部分,以及一个用于每个 xxx 寄存器输入的 next_xxx 信号。

architecture state_machine_raccincarre_arc of RaccinCarreSequentielle is
    type state is (s0_wait, s1_init, s2_calcul, s3_fini);
    signal pre_state, next_state: state;
    signal rx, rz, rv, next_rx, next_rz, next_rv: unsigned(2*N-1 downto 0);
    signal ri, next_ri: unsigned(N-1 downto 0);
begin
    state_register:process(reset,clk)
    begin
        if reset = '1' then
            pre_state <= s0_wait;
            rx <= (others => '0');
            rz <= (others => '0');
            ri <= (others => '0');
            rv <= (others => '0');
        elsif rising_edge(clk) then
            pre_state <= next_state;
            rx <= next_rx;
            rz <= next_rz;
            ri <= next_ri;
            rv <= next_rv;
        end if;
    end process state_register;

    state_machine: process(pre_state, state_done, x, rx, rz, rv, ri)
        variable tmpz : unsigned(2*N-1 downto 0);
    begin
        next_state <= pre_state;
        next_rx    <= rx;
        next_rz    <= rz;
        next_rv    <= rv;
        next_ri    <= ri;
        tmpz       := (others => '0');
        case pre_state is
            when s0_wait =>
                if state_done = '1' then
                    next_state <= s1_init;
                end if;
            when s1_init =>
                next_state <= s2_calcul;
                next_rx <= x;
                next_rz <= (others => '0');
                next_rv <= (others => '0');
                next_rv(2*N-2) <= '1';
                next_ri <= to_unsigned(N-1,N);
            when s2_calcul =>
                if ri > 0 then
                    next_ri <= ri - 1;
                    tmpz := rz + rv;
                    if rx > tmpz then
                        next_rx <= rx - tmpz;
                        tmpz := tmpz + rv;
                    else
                        tmpz := tmpz - rv;
                    end if;
                    next_rz <= '0' & tmpz(2*N-1 downto 1);
                    next_rv <= "00" & rv(2*N-1 downto 2);
                else
                    next_state <= s3_fini;
                end if;
            when s3_fini =>
                if state_done = '0' then
                    next_state <= s0_wait;
                end if;
        end case;
    end process state_machine;

    result <= rz;
    result_done <= '1' when pre_state = s3_fini else '0';
end architecture;

看到了吗?组合进程的敏感列表包含进程读取的all个信号,它赋值的信号总是赋值(感谢一开始的默认赋值),唯一的变量总是在使用之前分配(也感谢一开始的默认分配)。

请注意,由于一开始的默认分配,在综合时没有获得闩锁的风险。默认情况下:

next_xxx <= xxx;

赋值表示默认情况下 xxx 寄存器不应更改。一个有趣的副作用是您不再需要某些 else 语句。您可以替换:

        when s0_wait =>
            if state_done = '1' then
                next_state <= s1_init;
            else 
                next_state <= s0_wait;
            end if;

作者:

        when s0_wait =>
            if state_done = '1' then
                next_state <= s1_init;
            end if;

因为 else 子句已经是默认情况。

当然,也可能因为结构完全不同,所以不能完全按照您的意愿工作。但至少这应该是调试的良好起点。请记住合成过程的主要原则:

  1. 敏感列表必须包含进程读取的所有信号(VHDL 2008标准的all关键字是有帮助,如果你的工具支持的话),
  2. 它分配的信号(它的输出)必须分配每次过程恢复(最开始的默认分配可以是对初学者很方便),
  3. 变量必须总是在使用之前赋值(一开始的默认赋值对初学者来说很方便)。

小心,这 3 条黄金法则并不那么容易检查,尤其是在复杂的嵌套 ifcase 语句中。这就是为什么我总是建议初学者在一开始就使用默认分配的技巧。规则 #2 和 #3 变得微不足道。对于规则 #1,如果您的工具支持 VHDL 2008 标准的 all 关键字,请将其用于所有组合过程(不适用于同步过程):

state_machine: process(all)