我正在用VHDL实现一个简单的SPI主程序。我面临的问题是,在合成过程中,为ss和data_rdy创建了两个触发器。我认为对这些端口的输出总是被指定的,那么为什么要创建这些寄存器,以及如何处理它们呢?
我的代码如下所示,省略了没有ss或data_rdy的状态。
实体:
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;架构:
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;相关合成器输出:
===============================================================================
| 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被分割成两个寄存器?
发布于 2014-11-29 00:28:51
注册您的输出通常是一件好事:它允许更好地定义时间,这可以转换为更可靠的操作,特别是与外部设备,如SPI外围设备。
您所面临的问题(我认为)是,当您希望某个输出在某一特定状态时为真时,当您处于该状态时(在时钟进程内)分配该输出将导致时钟周期延迟。
David给出了一个答案:将所有的赋值移出时钟部分--或者完全离开这个过程,只依赖于“状态”信号。
但是,另一种方式将保持寄存器清洁的时间,并仍然消除这一周期的延迟。也就是说,将输出赋值提前到转换到该状态的任何状态,或者(一旦进入状态)不会从状态转换出来。例如,修改
when rx12 =>
data <= datasig;
data_rdy <= '1';
state <= done;以及向国家rx12的过渡
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_rdy和rx12总是同时声明,并为它们共享一个寄存器。
编辑:我回来再看一遍,注意到data <= datasig;也注册了,因此也晚了一个周期:虽然我只将data_rdy视为您提到的信号之一,但您需要考虑是否应该提前执行其他任务,比如data <= datasig;。(我想是这样的:在新数据出现之前,在循环中向data_rdy发出信号是违反直觉的!)
发布于 2014-11-28 23:58:52
,我面临的问题是,在合成过程中,为ss和data_rdy创建了两个触发器。我认为这些端口的输出总是被指定的,那么为什么要创建这些寄存器,以及如何处理它们呢?
data_rdy和ss的寄存器就在这里创建:
if rising_edge(clk) then
data_rdy <= '0';
ss <= '0';摆脱它们的方法是只将data_rdy和ss赋值给计算clk的if语句之外。
还有,为什么状态被分割成两个寄存器?
你有32个州,所以5张拖鞋听起来是对的。如果您查看报告中关于这两组触发器的最后两列,您会发现其中三组是同步设置的,两组触发器都是同步重置的。
这是关于:
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;因为您的同步干扰状态为空闲、启动或使用由状态驱动的输入多路复用器。
如果您有能力看到映射设计的示意图表示,这将具有启发性。
https://stackoverflow.com/questions/27196214
复制相似问题