首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为FSM中的输出端口创建寄存器,为什么?

为FSM中的输出端口创建寄存器,为什么?
EN

Stack Overflow用户
提问于 2014-11-28 21:36:14
回答 2查看 161关注 0票数 0

我正在用VHDL实现一个简单的SPI主程序。我面临的问题是,在合成过程中,为ssdata_rdy创建了两个触发器。我认为对这些端口的输出总是被指定的,那么为什么要创建这些寄存器,以及如何处理它们呢?

我的代码如下所示,省略了没有ssdata_rdy的状态。

实体:

代码语言:javascript
复制
library IEEE;
use IEEE.std_logic_1164.ALL;

entity mcu is
    port(clk      : in  std_logic;
         res      : in  std_logic;
         pc       : in  std_logic_vector(7 downto 0);
         pc_new   : in  std_logic;
         data_ack : in  std_logic;
         miso     : in  std_logic;
         data     : out std_logic_vector(12 downto 0);
         data_rdy : out std_logic;
         mosi     : out std_logic;
         sclk     : out std_logic;
         ss       : out std_logic);
end mcu;

架构:

代码语言:javascript
复制
library IEEE;
use IEEE.std_logic_1164.ALL;

architecture behaviour of mcu is
    -- r: send read command
    -- a: send address
    -- rx: receive data
    type state_t is (r0, r1, r2, r3, r4, r5, r6, r7,
                     a0, a1, a2, a3, a4, a5, a6, a7,
                     rx0, rx1, rx2, rx3, rx4, rx5, rx6, rx7, rx8, rx9, rx10, rx11, rx12,
                     idle, starting, done);
    signal state    : state_t                      := idle;
    signal datasig  : std_logic_vector(12 downto 0);
begin
    sclk <= clk;
    mosi <= datasig(12);

    sync : process(clk) is
    begin
        if rising_edge(clk) then
            data_rdy <= '0';
            ss       <= '0';

            if res = '1' then
                state <= idle;
            else
                datasig <= datasig(11 downto 0) & miso;

                if pc_new = '1' then
                    state <= starting;
                else
                    case state is
                    when idle =>
                        ss      <= '1';
                        datasig <= (others => '0');
                        state   <= idle;

                    ...

                    when rx12 =>
                        data     <= datasig;
                        data_rdy <= '1';
                        state    <= done;
                    when done =>
                        if data_ack = '1' then
                            state <= idle;
                        else
                            state <= done;
                        end if;
                end case;
                end if;
            end if;
        end if;
    end process sync;
end behaviour;

相关合成器输出:

代码语言:javascript
复制
===============================================================================
|    Register Name    |   Type    | Width | Bus | MB | AR | AS | SR | SS | ST |
===============================================================================
|    data_rdy_reg     | Flip-flop |   1   |  N  | N  | N  | N  | Y  | N  | N  |
|       ss_reg        | Flip-flop |   1   |  N  | N  | N  | N  | Y  | N  | N  |
|      data_reg       | Flip-flop |  13   |  Y  | N  | N  | N  | N  | N  | N  |
|      state_reg      | Flip-flop |   3   |  Y  | N  | N  | N  | N  | Y  | N  |
|      state_reg      | Flip-flop |   2   |  N  | N  | N  | N  | Y  | Y  | N  |
|     datasig_reg     | Flip-flop |  13   |  Y  | N  | N  | N  | N  | N  | N  |
===============================================================================

另外,为什么state被分割成两个寄存器?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-29 00:28:51

注册您的输出通常是一件好事:它允许更好地定义时间,这可以转换为更可靠的操作,特别是与外部设备,如SPI外围设备。

您所面临的问题(我认为)是,当您希望某个输出在某一特定状态时为真时,当您处于该状态时(在时钟进程内)分配该输出将导致时钟周期延迟。

David给出了一个答案:将所有的赋值移出时钟部分--或者完全离开这个过程,只依赖于“状态”信号。

但是,另一种方式将保持寄存器清洁的时间,并仍然消除这一周期的延迟。也就是说,将输出赋值提前到转换到该状态的任何状态,或者(一旦进入状态)不会从状态转换出来。例如,修改

代码语言:javascript
复制
            when rx12 =>
                data     <= datasig;
                data_rdy <= '1';
                state    <= done;

以及向国家rx12的过渡

代码语言:javascript
复制
            when rx11 =>
                if ready_to_go_to_rx12 then
                   data_rdy <= '1';  -- keep data_rdy synched with rx12
                   state    <= rx12;
                end if;

            when rx12 =>
                data     <= datasig;
                -- data_rdy <= '1'; -- no, because we leave state rx12 immediately
                state    <= done;

同样,对于具有相同问题的其他输出也是如此。

这很可能不会产生额外的逻辑,因为synth工具通常可以识别data_rdyrx12总是同时声明,并为它们共享一个寄存器。

编辑:我回来再看一遍,注意到data <= datasig;也注册了,因此也晚了一个周期:虽然我只将data_rdy视为您提到的信号之一,但您需要考虑是否应该提前执行其他任务,比如data <= datasig;。(我想是这样的:在新数据出现之前,在循环中向data_rdy发出信号是违反直觉的!)

票数 1
EN

Stack Overflow用户

发布于 2014-11-28 23:58:52

,我面临的问题是,在合成过程中,为ss和data_rdy创建了两个触发器。我认为这些端口的输出总是被指定的,那么为什么要创建这些寄存器,以及如何处理它们呢?

data_rdyss的寄存器就在这里创建:

代码语言:javascript
复制
    if rising_edge(clk) then
        data_rdy <= '0';
        ss       <= '0';

摆脱它们的方法是只将data_rdyss赋值给计算clk的if语句之外。

还有,为什么状态被分割成两个寄存器?

你有32个州,所以5张拖鞋听起来是对的。如果您查看报告中关于这两组触发器的最后两列,您会发现其中三组是同步设置的,两组触发器都是同步重置的。

这是关于:

代码语言:javascript
复制
    if rising_edge(clk) then
        data_rdy <= '0';
        ss       <= '0';

        if res = '1' then
            state <= idle;
        else
            datasig <= datasig(11 downto 0) & miso;

            if pc_new = '1' then
                state <= starting;
            else
                case state is
                when idle =>
                    ss      <= '1';
                    datasig <= (others => '0');
                    state   <= idle;

因为您的同步干扰状态为空闲、启动或使用由状态驱动的输入多路复用器。

如果您有能力看到映射设计的示意图表示,这将具有启发性。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27196214

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档