FPGA:在同一过程中同时使用下降沿和上升沿
FPGA : using both falling and rising edge in same process
我是 fpga 和 vhdl 新手..
我的开发环境如下
FPGA:斯巴达 6 XC6SLX9
编译器:ISE 14.04
模拟器:Isim
我正在做一个简单的计数器,但是有些地方我看不懂。
下面的代码是我写的。我期望的是 w_count
在时钟的每个下降沿增加,并在时钟上升沿期间 w_count
达到 N_data
时重置为 0。编译过程没有问题,模拟也和我预想的一样好。但是当应用于真正的fpga时,w_count
每次触发都会递增,但在达到N_data
..
时并未初始化为零
w_state_proc : process(r_clk, reset_n_clean)
begin
if(reset_n_clean = '0') then
w_count <= 0;
elsif(r_clk'event and r_clk = '0') then
if(state = write_state and w_proc = '1') then
w_count <= w_count + 1;
end if;
elsif(r_clk'event and r_clk = '1') then
if(w_count = N_data) then
w_count <= 0;
end if;
end if;
end process w_state_proc;
当我改变两个elsif
语句的位置时,w_count
根本没有增加..
w_state_proc : process(r_clk, reset_n_clean)
begin
if(reset_n_clean = '0') then
w_count <= 0;
elsif(r_clk'event and r_clk = '1') then
if(w_count = N_data) then
w_count <= 0;
end if;
elsif(r_clk'event and r_clk = '0') then
if(state = write_state and w_proc = '1') then
w_count <= w_count + 1;
end if;
end if;
end process w_state_proc;
我看到很多反馈说不推荐这些语句,但我不明白为什么这些语句会导致这个问题..
您的 FPGA 在通用结构中没有双数据速率 (DDR) 触发器,因此不推荐使用它 - "as is" 它无法实现所需的功能。
此外,您正在使用异步重置。虽然可能,但也强烈不推荐,因为 FPGA 已经具有同步复位触发器,因此它不需要任何额外的逻辑,这与 ASIC 不同,即使没有复位,您也会获得每个信号的已知值。异步复位会给您以某种方式实现时序收敛带来麻烦。
在您的示例中,确实不需要 DDR FF。看起来你有这种行为的原因是 w_count 可以在时钟周期之间被清除,这样 w_count 在递增时永远不会是 N_data 。为什么不将它与小一个的值进行比较呢?
或者,您可以使用变量(非常小心!)来实现非常相似的行为:
w_state_proc : process(r_clk) is
variable v_count : integer range 0 to N_data;
begin
if (rising_edge(r_clk)) then
v_count := w_count;
if(state = write_state and w_proc = '1') then
v_count := v_count + 1;
end if;
if(reset_n_clean = '0' or v_count = N_data) then
w_count <= 0;
else
w_count <= v_count;
end if;
end if;
end process w_state_proc;
如果你 真的 需要 w_count 在半个时钟周期内具有 N_data 的值,你总是可以将时钟设置为两倍快速并每隔一个时钟周期使用启用信号,并将其与您的管道一起传播。这会让你陷入一大堆其他(非常有教育意义的)麻烦中,但这是可行的。
我是 fpga 和 vhdl 新手..
我的开发环境如下
FPGA:斯巴达 6 XC6SLX9
编译器:ISE 14.04
模拟器:Isim
我正在做一个简单的计数器,但是有些地方我看不懂。
下面的代码是我写的。我期望的是 w_count
在时钟的每个下降沿增加,并在时钟上升沿期间 w_count
达到 N_data
时重置为 0。编译过程没有问题,模拟也和我预想的一样好。但是当应用于真正的fpga时,w_count
每次触发都会递增,但在达到N_data
..
w_state_proc : process(r_clk, reset_n_clean)
begin
if(reset_n_clean = '0') then
w_count <= 0;
elsif(r_clk'event and r_clk = '0') then
if(state = write_state and w_proc = '1') then
w_count <= w_count + 1;
end if;
elsif(r_clk'event and r_clk = '1') then
if(w_count = N_data) then
w_count <= 0;
end if;
end if;
end process w_state_proc;
当我改变两个elsif
语句的位置时,w_count
根本没有增加..
w_state_proc : process(r_clk, reset_n_clean)
begin
if(reset_n_clean = '0') then
w_count <= 0;
elsif(r_clk'event and r_clk = '1') then
if(w_count = N_data) then
w_count <= 0;
end if;
elsif(r_clk'event and r_clk = '0') then
if(state = write_state and w_proc = '1') then
w_count <= w_count + 1;
end if;
end if;
end process w_state_proc;
我看到很多反馈说不推荐这些语句,但我不明白为什么这些语句会导致这个问题..
您的 FPGA 在通用结构中没有双数据速率 (DDR) 触发器,因此不推荐使用它 - "as is" 它无法实现所需的功能。
此外,您正在使用异步重置。虽然可能,但也强烈不推荐,因为 FPGA 已经具有同步复位触发器,因此它不需要任何额外的逻辑,这与 ASIC 不同,即使没有复位,您也会获得每个信号的已知值。异步复位会给您以某种方式实现时序收敛带来麻烦。
在您的示例中,确实不需要 DDR FF。看起来你有这种行为的原因是 w_count 可以在时钟周期之间被清除,这样 w_count 在递增时永远不会是 N_data 。为什么不将它与小一个的值进行比较呢?
或者,您可以使用变量(非常小心!)来实现非常相似的行为:
w_state_proc : process(r_clk) is
variable v_count : integer range 0 to N_data;
begin
if (rising_edge(r_clk)) then
v_count := w_count;
if(state = write_state and w_proc = '1') then
v_count := v_count + 1;
end if;
if(reset_n_clean = '0' or v_count = N_data) then
w_count <= 0;
else
w_count <= v_count;
end if;
end if;
end process w_state_proc;
如果你 真的 需要 w_count 在半个时钟周期内具有 N_data 的值,你总是可以将时钟设置为两倍快速并每隔一个时钟周期使用启用信号,并将其与您的管道一起传播。这会让你陷入一大堆其他(非常有教育意义的)麻烦中,但这是可行的。