VHDL编码问题:( 你好!我一直在研究这个问题。我觉得这是一个我不太明白的开始问题。
- 我正在访问内部存储器,每行4行2位数。我已经能够很好地读取和写入内存,我的问题是增加我将存储下一个数据集的地址。
- 我的单位由具有三种状态的FSM控制。空闲,芦苇和仪式。我有三个内部信号,addressin:指向下一个要读取的地址的指针,addressout:指向下一个要写入的地址的指针和addressall,该地址将进入实际的存储器阶段。
PROCESS (y)
BEGIN
CASE y IS
WHEN I=>
enable<='0';
WHEN reed=>
enable<='0';
IF (addressin="00" OR addressin="01" OR addressin="10") THEN
addressin<=addressin+"01";
ELSE
addressin<="00";
END IF;
addressall<=addressin;
WHEN rite=>
enable<='1';
IF (addressout="00" OR addressout="01" OR addressout="10") THEN
addressout<=addressout+1;
ELSE
addressout<="00";
END IF;
addressall<=addressout;
END CASE;
END PROCESS;
memorystage: memory PORT MAP (clck, NOT reset, NOT enable, addressall, datain, dataout);
当y发生变化时,过程将激活(状态变化是代码未见。)我的问题是,地址将改变,地址输出将改变,地址也将改变......但是从来没有一个,和从来没有在任何顺序逻辑...(我有这个在十六进制显示中看到)例如我会得到地址:3 3 1 0 3 0 3 0 2 0 2 1 0 ....与其他两个地址相同信号。我不知道我做错了什么。这只是一个大项目的一部分,所以我把它拉出去自己动手。 :(我做错了什么?谢谢。-Jenn
答案 0 :(得分:1)
我认为你已经成为VHDL的牺牲品(very well defined,但往往会让新手感到困惑)信号更新规则。另见这个问题.. When do signals get assigned in VHDL?
信号仅在流程结束时(或wait
发生时更新,但我们暂时保留该选项!)
IF (addressin="00" OR addressin="01" OR addressin="10") THEN
addressin<=addressin+"01";
ELSE
addressin<="00";
END IF;
addressall<=addressin;
addressall
将获取之前的值addressin
,而不是您刚刚设置的值,因为它尚未更新。
要获得所需的行为,请在此过程中将addressin
更改为variable
(并且您必须将所有<=
分配更改为:=
分配) 。变量按您希望的方式工作 - 立即应用更新。
我几乎总是在过程中使用变量来保留信号以便与其他过程进行通信。
答案 1 :(得分:0)
不确定您是否可以使用同步设计,但我将它们放在一起。如果您处于簧片或仪式状态,此设计将通过您的地址指针(addressin,addressout)增加,如时钟更新。
PROCESS (y, clk) BEGIN
IF rising_edge(clk) then
enable<='0';
CASE y IS
WHEN I=>
WHEN reed=>
IF(addressin ="11") then
addressin <= "00";
ELSE
addressin <= addressin + 1;
END IF;
addressall<=addressin;
WHEN rite=>
enable<='1';
IF(addressout ="11") then
addressout <= "00";
ELSE
addressout <= addressin + 1;
END IF;
addressall<=addressout;
END CASE;
END IF;
END PROCESS;
memorystage: memory PORT MAP (clck, NOT reset, NOT enable, addressall, datain, dataout);
如果您只希望每次更改状态更新一次,则可以执行类似
的操作prev_state : PROCESS (y,clk) BEGIN
IF rising_edge(clk) then
ybuff <= y;
END IF;
END PROCESS;
PROCESS (y, clk) BEGIN
IF rising_edge(clk) then
IF (ybuff /= y) then
enable <= '0';
CASE y IS
....
....
如果您需要其他内容,则需要向我们提供更多代码。这有点被黑(因为我没有你的状态逻辑或更新信号)
我同意Martin的说法,你当前更新的addressall不是正确的方法。就像他说你可以使用变量来解决这个问题,或者如果你真的想要保留它,你应该将它放在一个单独的进程块中,更新addressall以使奇怪性更加明确和受控制。现在(并且我发布了第二个更新程序)你将始终是指针后面的一个地址(并且在状态机后面有一个完整的循环)
答案 2 :(得分:0)
需要考虑的其他几点:
1)输入/输出地址的递增方式不一致:addressin<=addressin+"01";
和addressout<=addressout+1;
。这些赋值的行为将取决于操作数的信号类型,这就是为什么这些信息有用,尽管这可能不是一个真正的问题。
2)假设地址信号的任何变化与开启y
直接相关应该是相对安全的,因为这是此过程中灵敏度列表中唯一的信号。您是否在波形查看器中检查了y
的值以及地址?
y
上的更改敏感。因此,此过程隐含的任何内存元素都将完全忽略时钟,并且仅受输入y
上的更改的影响。换句话说,为了推进读指针,y
必须在idle
和reed
状态之间切换。您必须决定这是否是预期的,或者逻辑是否应该在reed
y
上存在Library ieee;
Use ieee.std_logic_1164.all;
Use ieee.numeric_std.all;
Entity test Is
End Entity;
Architecture main of test Is
Signal enable, clock : std_logic := '0';
Signal addressin, addressout, addressall : unsigned(0 to 1) := "00";
Type op_t is (reed, idle, rite);
Signal y : op_t;
Signal done : boolean;
Begin
clocks: process
begin
if not done then
clock <= not clock;
wait for 0.5 ns;
else
wait;
end if;
end process;
PROCESS (clock, y)
BEGIN
if rising_edge(clock) then
CASE y IS
WHEN idle=>
enable<='0';
WHEN reed=>
enable<='0';
IF (addressin="00" OR addressin="01" OR addressin="10") THEN
addressin<=addressin+1;
ELSE
addressin<="00";
END IF;
addressall<=addressin;
WHEN rite=>
enable<='1';
IF (addressout="00" OR addressout="01" OR addressout="10") THEN
addressout<=addressout+1;
ELSE
addressout<="00";
END IF;
addressall<=addressout;
END CASE;
end if;
END PROCESS;
main: Process
Begin
y <= idle;
wait for 1 ns;
y <= reed;
wait for 1 ns;
assert addressall = "00";
wait for 1 ns;
assert addressall = "01";
wait for 1 ns;
assert addressall = "10";
wait for 1 ns;
assert addressall = "11";
y <= idle;
wait for 1 ns;
done <= true;
wait;
End Process;
End Architecture;
状态的每个时钟周期推进读指针。对于存储器元件不接收指定时钟可能是非传统的,因为时钟接受特殊处理以简化静态时序分析,但语言不禁止它(对下游工具不能保证相同)。
一般来说,听起来你很清楚你想要完成什么并掌握一些VHDL的细微差别,所以下一步是进一步隔离意外行为。更多代码可以帮助排除一些潜在的问题,但也许同时测试您的假设并提供可重现的示例的最佳方法是创建一个说明意外行为的测试平台。
例如,这是一个测试平台,用于处理您的过程的时钟副本。
{{1}}