FSM,乘积计数之和

FSM, sum of products count

我的 VHDL 项目有一个问题。代码如下:

注册模块:

library ieee;
use ieee.std_logic_1164.all;

entity reg is 
port(
    clk, rst : in std_logic;
    d           : in std_logic_vector(23 downto 0);
    q           : out std_logic_vector(23 downto 0)
);
end reg;

architecture arch of reg is

signal q_reg, q_next : std_logic_vector(23 downto 0);

begin
    process(clk, rst)
        begin
        if (rst ='1') then
                q_reg <= (others => '0');
        elsif rising_edge(clk) then
            q_reg <= q_next;
        end if;
    end process;

    q_next <= d;
    q <= q_reg;

end arch;

多个模块:

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


entity mul is
port (
    a : in std_logic_vector(7 downto 0);
    b : in std_logic_vector(15 downto 0);
    r : out std_logic_vector(23 downto 0)
);
end mul;

architecture arch of mul is

signal result : signed (23 downto 0);
begin
        result <= signed(a) * signed(b);
        r        <= std_logic_vector(result);
end arch;

加法器模块:

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

entity add is
port (
    a,b : in std_logic_vector(23 downto 0);
    s    : out std_logic_vector(23 downto 0)
);
end add;

architecture arch of add is

signal result : signed(23 downto 0);
begin
    result <= signed(a) + signed(b);
    s        <= std_logic_vector(result);
end arch;

ALU模块:

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

entity alu is 
port (
    clk, rst : in std_logic;
    data        : in std_logic_vector(7 downto 0);
    cof     : in std_logic_vector(15 downto 0);
    y           : out std_logic_vector(23 downto 0)
);
end alu;

architecture arch of alu is

signal mul_in_a               : std_logic_vector(7 downto 0);
signal mul_in_b               : std_logic_vector(15 downto 0);
signal mul_out            : std_logic_vector(23 downto 0);

signal add_in_a, add_in_b : std_logic_vector(23 downto 0);
signal add_out                : std_logic_vector(23 downto 0);

signal reg_in, reg_out    : std_logic_vector(23 downto 0);

component mul
    port(
        a : in std_logic_vector(7 downto 0);
        b : in std_logic_vector(15 downto 0);
        r : out std_logic_vector(23 downto 0)   
    );
end component;

component add
    port(
        a : in std_logic_vector(23 downto 0);
        b : in std_logic_vector(23 downto 0);
        s : out std_logic_vector(23 downto 0)
    );
end component;

component reg
    port(
        clk  : in std_logic;
        rst  : in std_logic;
        d     : in std_logic_vector(23 downto 0);
        q    : out std_logic_vector(23 downto 0)
    );
end component;

begin

b1:mul port map(
    a => mul_in_a,
    b => mul_in_b,
    r => mul_out
);

b2:add port map (
    a => add_in_a,
    b => add_in_b,
    s => add_out
);

b3:reg port map (
    clk => clk,
    rst => rst,
    d   => reg_in,
    q   => reg_out
);

mul_in_a <= data;
mul_in_b <= cof;

add_in_a <= mul_out;
add_in_b <= reg_out;

reg_in  <= add_out;

       y <= reg_out;
end arch;

顶级模块,带 fsm:

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

entity top is
port(
    clk   : in std_logic;
    rst   : in std_logic;
    rst_a     : in std_logic;
    data_in : in std_logic_vector(7 downto 0);
    data_out: out std_logic_vector(23 downto 0);
    Yacc      :  out unsigned(3 downto 0)
);
end top;

architecture arch of top is

type STYPE is (load,count,result);
signal cof_alu_reg, cof_alu_next                              : std_logic_vector(15 downto 0);
signal dt_in_alu_reg,dt_in_alu_next                       : std_logic_vector(7 downto 0);
signal datao                              : std_logic_vector(23 downto 0);
signal state_reg, state_next          : STYPE;
signal adress_reg, adress_next                            :unsigned(3 downto 0);
signal data_out_reg, data_out_next : std_logic_vector(23 downto 0);

type cof_table is array ( 8 downto 0) of std_logic_vector( 15 downto 0);
type data_table is array ( 8 downto 0) of std_logic_vector(7 downto 0);
signal Yacc_reg, Yacc_next :  unsigned(3 downto 0);
signal clr : std_logic;
signal datat                              : data_table;
signal coft                               : cof_table;

component alu
port(
    clk, rst : in std_logic;
    data        : in std_logic_vector(7 downto 0);
    cof     : in std_logic_vector(15 downto 0);
    y           : out std_logic_vector(23 downto 0)
     );
end component;

begin

a1:alu port map (
    clk => clk,
    rst => clr,
    cof => cof_alu_reg,
    data => dt_in_alu_reg,
    y =>  datao
);

process(rst, clk)
begin
    if rst = '1' then
        state_reg <= load;
    elsif rising_edge(clk) then
        state_reg <= state_next;
    end if;
end process;



process(rst, clk)
begin
    if rst = '1' then
        cof_alu_reg <= (others => '0');
        dt_in_alu_reg <= (others => '0');
        adress_reg <= "0000";
        data_out_reg <= (others => '0');
        Yacc_reg <= "0000";
    elsif rising_edge(clk) then
        cof_alu_reg <= cof_alu_next;
        dt_in_alu_reg <= dt_in_alu_next;
        adress_reg <= adress_next;
        data_out_reg <= data_out_next;
        Yacc_reg <= Yacc_next;
    end if;
end process;


process(state_reg, cof_alu_reg,dt_in_alu_reg,adress_reg,Yacc_reg,datao,clr)
begin
    state_next <= state_reg;
    cof_alu_next <= cof_alu_reg;
    dt_in_alu_next <= dt_in_alu_reg;
    adress_next <= adress_reg;
    data_out_next <= data_out_reg;
    Yacc_next <= Yacc_reg;

    coft(0) <= "0000000001101110";
    coft(1) <= "1111111110111011";
    coft(2) <= "1111111011000000";
    coft(3) <= "0000010001000101";
    coft(4) <= "0000100110100110";
    coft(5) <= "0000010001000101";
    coft(6) <= "1111111011000000";
    coft(7) <= "1111111110111011";
    coft(8) <= "0000000001101110";

    Yacc <= Yacc_reg;
    case state_reg is
        when load =>
        if adress_reg < "1001" then
            datat(to_integer(adress_reg)-1) <= data_in;
            Yacc_next <= adress_reg;
            adress_next <= adress_reg + "0001";
            state_next <= load;
        elsif adress_reg = "1001" then
            datat(to_integer(adress_reg)-1) <= data_in;
            Yacc_next <= adress_reg;
            adress_next <= "0000";
            state_next <= count;
        end if;

        when count =>
        if adress_reg < "1001" then
            dt_in_alu_next <= datat(to_integer(adress_reg)-1);
            cof_alu_next    <= coft(to_integer(adress_reg)-1);
            Yacc_next <= adress_reg;
            adress_next <= adress_reg + "0001";
            state_next <= count;
        elsif adress_reg = "1001" then
            dt_in_alu_next <= datat(to_integer(adress_reg-1));
            cof_alu_next    <= coft(to_integer(adress_reg)-1);
            state_next <= result;
            adress_next <= "0000";
            Yacc_next <= adress_reg;
        end if;

        when result =>
            data_out_next <= datao;
            Yacc_next <= adress_reg;
            adress_next <= adress_reg + "0001";
            state_next <= load;


        when others =>
            state_next <= load;

    end case;
end process;

    data_out    <= data_out_reg;


end arch;

这个简单的系统计算产品总和。在前九个时钟节拍期间,我从输入中获取样本,我使用地址来增加下一个位置以保存样本。我的问题是当系统进入九个时钟节拍时,样本不会保存到内存中,从而减少了最终结果。有人知道错误在哪里吗?

这是我的建议。
改进:

  • 减少异步重置
  • 从 FSM 中提取数据流
  • 为正确的重置传播引入了状态空闲
  • 更正地址计算 -> 没有 -1
  • 将系数定义为常量
  • 删除了冗余寄存器

编辑 1:

忘了alu有1个周期的延迟。所以你可以在状态计数中计数到 9 或在计数和结果之间插入一个 nop 状态。

为什么datat索引计算错误?
- 上电后和每次复位后,adress_reg 为零,state 为负载。
-> if adress_reg < "1001" then 是当前状态(负载)下的活动分支
-> data_in 写入索引 to_integer("0000")-1)
=> 这是 -1
=> 模拟应该给出一个超出范围的错误

为什么 cof_alu_regdt_in_alu_reg 上的附加寄存器是错误的?
- FSM 为状态计数中的 alu 选择适当的系数和输入。
- 这些值已注册(1 个周期延迟)
- alu模块以另一个延迟周期执行计算 => 因此,在为 alu 分配最后一个输入值之后,在 data_out_reg 捕获结果之前必须有 2 个周期的延迟。

修改源码(未模拟):

    architecture arch of top is

        type STYPE is (idle,load,count,nop,result);
        signal state_reg            : STYPE     := idle;
        signal state_next           : STYPE;

        signal address_rst          : std_logic;
        signal address_reg          : unsigned(3 downto 0)                      := (others => '0');

        type cof_table  is array (8 downto 0) of std_logic_vector(15 downto 0);
        type data_table is array (8 downto 0) of std_logic_vector(7 downto 0);

        signal datat_en             : std_logic;
        signal datat                : data_table;

        signal cof_alu_next         : std_logic_vector(15 downto 0);
        signal dt_in_alu_next       : std_logic_vector(7 downto 0);

        signal data_out_next        : std_logic_vector(23 downto 0);
        signal data_out_en          : std_logic;
        signal data_out_reg         : std_logic_vector(23 downto 0)     := (others => '0');

        constant coft                   : cof_table := (
            0 => "0000000001101110",
            1 => "1111111110111011",
            2 => "1111111011000000",
            3 => "0000010001000101",
            4 => "0000100110100110",
            5 => "0000010001000101",
            6 => "1111111011000000",
            7 => "1111111110111011",
            8 => "0000000001101110"
        );

    begin

        # no registers needed, because oft is constant and datat is already registered
        cof_alu_next    <= coft(to_integer(address_reg));
        dt_in_alu_next  <= datat(to_integer(address_reg));

        a1:alu port map (
                clk => clk,
                rst => clr,
                cof => cof_alu_next,
                data => dt_in_alu_next,
                y =>  data_out_next
        );

        process(rst, clk)
        begin
                if rst = '1' then
                        state_reg <= idle;
                elsif rising_edge(clk) then
                        state_reg <= state_next;
                end if;
        end process;

        # rewritten to synchronous registers
        process(clk)
        begin
                if rising_edge(clk) then
                    # address counter
                    # count if reset is low
                    if (address_rst = '1') then
                        address_reg     <= (others => '0');
                    else
                        address_reg     <= address_reg + 1;
                    end if;

                    # datatable
                    # store data if enabled
                    if (datat_en = '1') then
                        datat(to_integer(address_reg)) <= data_in;
                    end if;

                    # result register
                    if (data_out_en = '1') then
                        data_out_reg    <= data_out_next;
                    end if;
                end if;
        end process;


        process(state_reg, address_reg)
        begin
            state_next          <= state_reg;

            address_rst         <= '0';
            datat_en                <= '0';
            data_out_en         <= '0';

            case state_reg is
                when idle =>
                    address_rst <= '1';
                    state_next  <= load;                # add a condition if needed

                when load =>
                    datat_en        <= '1';
                    Yacc_next       <= address_reg;

                    if (address_reg = datat'high) then
                        address_rst <= '1';
                        state_next  <= count;
                    end if;

                when count =>
                    if (address_reg = datat'high) then
                        address_rst <= '1';
                        state_next  <= nop;
                    end if;

                when nop =>
                  state_next        <= result;

                when result =>
                    data_out_en     <= '1';
                    state_next      <= idle;        # if you want to go to count: assert address_rst in this state

                when others =>
                    state_next <= load;

            end case;
        end process;

        # outputs
        Yacc            <= address_reg when rising_edge(clk);       # delay Yacc output by one cycle (short form)
        data_out    <= data_out_reg;
    end arch;