一些学到的或自己总结的VHDL经验点滴,纪录下来,以免以后忘记了。因为有些是自己总结的,肯定有错误或不周之处,欢迎高手指正!内容逐步补充中。
1。如何判断一个process综合结果是组合逻辑还是时序逻辑?
A:一个比较简单的办法是看敏感信号和条件语句的条件,如果是电平触发的,很可能是时序逻辑;如果是边缘触发的,则是时序逻辑。
2。采用二进程状态机比单进程状态机好,把同步时序和组合逻辑分开,有利于综合器优化代码。碰到需要对时钟计数的时候,可能会觉得用单进程方便点,如果要用双进程结构的话,可以把计数放在同步进程里,给出一个计数值,而组合进程用这个值作为输入,这样保证组合进程仍然是组合逻辑(里面不含边沿触发条件)。
3。采用统一的接口时序。一个FPGA设计里通常都是有多个模块,如果各个模块的接口都不相同,那将会带来不少麻烦。因此尽可能采用统一的接口时序。RAM形式接口(一般由片选、地址、输入(n)、输出(n)、读写信号组成,实际应用时可增加中断信号)简单、快速,通常是第一选择。各个模块都采用RAM接口后,对模块的操作信号和时序都是一样的,所不同的就是对不同的地址写入不同数据,以使用各模块的功能,而且可以统一挂接到总线上。所以一般单片机内部各种模块都是采用相同的接口,挂接到内部总线上,实现于CPU内核的连接。
例如一个收发器的内部接口例子:
--
-- 寄存器定义
-- 地址 名称 R/W 说明
-- 00 DATATRANS R 8 bit要发送的数据
-- 00 DATARECV W 8 bit接收到的数据
-- 01 CONTROL R/W 控制寄存器:
-- [0]=收发模式 0:接收模式;1:发送模式
-- [1..7]=保留
-- 10 STATUS R/W 状态寄存器
-- [0]=接收数据就绪 读到1时有数据收到;写入1时清除中断
-- [1]=发送数据完成 读到1时发送数据完成;写入1时清除中断
-- [2..7]=保留
-- 11 NONE 保留
--
entity transceiver is
port(
-- 收发模块接口
clkin : in std_logic; -- 50MHz clock input
reset : in std_logic;
address : in std_logic_vector(1 downto 0); -- 寄存器地址
datain : in std_logic_vector(7 downto 0); -- 数据输入
dataout : out std_logic_vector(7 downto 0); -- 数据输出
write : in std_logic; -- 写使能
cs : in std_logic; -- 片选
irq : out std_logic; -- 中断输出
-- 外部接口
rxd : in std_logic; -- 接max481 RO
txd : out std_logic; -- 接max481 DI
...
);
end entity transceiver;
(再罗嗦一句:这个收发器后来使用了fifo作为接口使用起来也是很方便)。
4。function/procedure内必须是组合逻辑吗?由于function/procedure是立刻返回的,如果是一个需要几个时钟才输出结果的时序逻辑,那调用者怎么知道它什么时候返回呢?所以我觉得应该是组合逻辑,但目前还没找到证实的资料,是否正确,望高手指点!
5。Altera不建议设计者在FPGA内部使用三态端口。因为Altera的产品中只有IO部分有三态门,而在内部逻辑电路只能用多路器实现,因此一般不要在内部使用三态门。同时Altera指出:其实内部三态门毫无意义。
6。理解敏感信号。敏感信号是并发语句的必要要素,指明了并发语句被执行的条件。敏感信号有显式和隐式,对于PROCESS,敏感信号显式说明;对于并发信号代入(a <= b),隐含指明了b是 敏感信号;对于条件信号代入(q <= "00" WHEN sel = "0" ELSE q <= "11"),WHEN后面判断的信号sel就是隐含的敏感信号;对于选择信号代入(WITH sel SELECT q <= "00" WHEN 0 ....),WITH后的sel就是隐含的敏感信号。要注意的是,IF语句里条件判断的信号并不是敏感信号,而只是分支条件,所以IF语句只能用在进程内,不是并发语句。比较一下IF语句和WITH语句,可以看出IF条件中的信号只是单纯起一个分支条件的作用,而WITH后的信号则起到分枝条件和敏感信号双重作用。这应该是VHDL语言为了让IF与PROCESS结合得到强大表达力的设计吧!
1。如何判断一个process综合结果是组合逻辑还是时序逻辑?
A:一个比较简单的办法是看敏感信号和条件语句的条件,如果是电平触发的,很可能是时序逻辑;如果是边缘触发的,则是时序逻辑。
2。采用二进程状态机比单进程状态机好,把同步时序和组合逻辑分开,有利于综合器优化代码。碰到需要对时钟计数的时候,可能会觉得用单进程方便点,如果要用双进程结构的话,可以把计数放在同步进程里,给出一个计数值,而组合进程用这个值作为输入,这样保证组合进程仍然是组合逻辑(里面不含边沿触发条件)。
3。采用统一的接口时序。一个FPGA设计里通常都是有多个模块,如果各个模块的接口都不相同,那将会带来不少麻烦。因此尽可能采用统一的接口时序。RAM形式接口(一般由片选、地址、输入(n)、输出(n)、读写信号组成,实际应用时可增加中断信号)简单、快速,通常是第一选择。各个模块都采用RAM接口后,对模块的操作信号和时序都是一样的,所不同的就是对不同的地址写入不同数据,以使用各模块的功能,而且可以统一挂接到总线上。所以一般单片机内部各种模块都是采用相同的接口,挂接到内部总线上,实现于CPU内核的连接。
例如一个收发器的内部接口例子:
--
-- 寄存器定义
-- 地址 名称 R/W 说明
-- 00 DATATRANS R 8 bit要发送的数据
-- 00 DATARECV W 8 bit接收到的数据
-- 01 CONTROL R/W 控制寄存器:
-- [0]=收发模式 0:接收模式;1:发送模式
-- [1..7]=保留
-- 10 STATUS R/W 状态寄存器
-- [0]=接收数据就绪 读到1时有数据收到;写入1时清除中断
-- [1]=发送数据完成 读到1时发送数据完成;写入1时清除中断
-- [2..7]=保留
-- 11 NONE 保留
--
entity transceiver is
port(
-- 收发模块接口
clkin : in std_logic; -- 50MHz clock input
reset : in std_logic;
address : in std_logic_vector(1 downto 0); -- 寄存器地址
datain : in std_logic_vector(7 downto 0); -- 数据输入
dataout : out std_logic_vector(7 downto 0); -- 数据输出
write : in std_logic; -- 写使能
cs : in std_logic; -- 片选
irq : out std_logic; -- 中断输出
-- 外部接口
rxd : in std_logic; -- 接max481 RO
txd : out std_logic; -- 接max481 DI
...
);
end entity transceiver;
(再罗嗦一句:这个收发器后来使用了fifo作为接口使用起来也是很方便)。
4。function/procedure内必须是组合逻辑吗?由于function/procedure是立刻返回的,如果是一个需要几个时钟才输出结果的时序逻辑,那调用者怎么知道它什么时候返回呢?所以我觉得应该是组合逻辑,但目前还没找到证实的资料,是否正确,望高手指点!
5。Altera不建议设计者在FPGA内部使用三态端口。因为Altera的产品中只有IO部分有三态门,而在内部逻辑电路只能用多路器实现,因此一般不要在内部使用三态门。同时Altera指出:其实内部三态门毫无意义。
6。理解敏感信号。敏感信号是并发语句的必要要素,指明了并发语句被执行的条件。敏感信号有显式和隐式,对于PROCESS,敏感信号显式说明;对于并发信号代入(a <= b),隐含指明了b是 敏感信号;对于条件信号代入(q <= "00" WHEN sel = "0" ELSE q <= "11"),WHEN后面判断的信号sel就是隐含的敏感信号;对于选择信号代入(WITH sel SELECT q <= "00" WHEN 0 ....),WITH后的sel就是隐含的敏感信号。要注意的是,IF语句里条件判断的信号并不是敏感信号,而只是分支条件,所以IF语句只能用在进程内,不是并发语句。比较一下IF语句和WITH语句,可以看出IF条件中的信号只是单纯起一个分支条件的作用,而WITH后的信号则起到分枝条件和敏感信号双重作用。这应该是VHDL语言为了让IF与PROCESS结合得到强大表达力的设计吧!