VHDL 锁存器问题(触发器不是一个选项)
VHDL latch issues (flip-flops are not an option)
我必须设计一个带有 RAM 的小型 CPU,但我遇到了一个我无法处理的问题。首先,我的代码:
这是内存
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity memory is
Port(
clk: IN std_logic;
instruction: IN std_logic;
address : IN std_logic_vector(0 to 15);
ibus: IN std_logic_vector(0 to 7);
obus: OUT std_logic_vector(0 to 7)
);
end memory;
architecture Behavioral of memory is
type memArr is array (integer range <> ) of std_logic_vector(0 to 7);
signal mem: memArr (0 to 65535);
signal rom: memArr (0 to 128);
signal ram: memArr (0 to 65407);
begin
-- LOAD/STORE Test
rom(0) <= "10100110"; -- step 1: (constant) load data1 into reg_addr1
rom(1) <= "00000000"; -- this one/
rom(2) <= "11100111"; -- step 2: (direct) load data2 from following address into reg_addr2
rom(3) <= "00000000"; -- this address
rom(4) <= "01000000"; -- contains data2/
rom(5) <= "10100000"; -- step 3: (constant) load followig data into reg_1
rom(6) <= "01010101"; -- this one/
rom(7) <= "10001000"; -- step 4: (indirect) store data in reg_1 to adress in reg_addr 1 + 2/
rom(64) <= "00000000"; -- data2 from step 2
mem(0 to 128) <= rom;
reading: process (clk, instruction, address)
begin
if clk ='1' and instruction = '0' then
obus <= mem(conv_integer(unsigned(address)));
end if;
end process;
writing: process (clk, instruction, address, ibus)
begin
if clk ='1' and instruction = '1' then
ram(conv_integer(unsigned(address))) <= ibus;
end if;
end process;
end Behavioral;
这是CPU:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity cpu is
Port(
clk: IN std_logic;
rst: IN std_logic;
instruction: OUT std_logic;
address : OUT std_logic_vector(0 to 15);
obus: OUT std_logic_vector(0 to 7);
ibus: IN std_logic_vector(0 to 7)
);
end cpu;
architecture Behavioral of cpu is
--signal reg_1, reg_2, reg_3, reg_4, reg_5, reg_acc, reg_addr1, reg_addr2: std_logic_vector(0 to 7);
signal pointer, s_pointer: std_logic_vector(0 to 15);
signal state, s_state, test: integer range 0 to 3;
signal read3, s_read3, execute, s_execute: std_logic;
type reg is array (integer range <>) of std_logic_vector(0 to 7);
signal registers: reg (0 to 7);
signal handler: reg (0 to 2);
begin
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
---
--- Slave process (runs at '0')
---
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
slave: process (clk, s_pointer, s_state, s_read3, s_execute)
begin
if clk = '0' then
pointer <= s_pointer;
state <= s_state;
read3 <= s_read3;
execute <= s_execute;
end if;
end process;
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
---
--- Master process (runs at '1')
---
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
master: process (clk, rst, ibus, pointer, state, read3, execute)
begin
if rst = '1' then
s_state <= 0;
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
---
--- FSM to read instructions
---
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
elsif clk = '1' and state = 0 then
s_state <= 1;
s_pointer <= "0000000000000000";
address <= "0000000000000000";
s_read3 <= '0';
s_execute <= '0';
instruction <= '0';
handler(0) <= "ZZZZZZZZ";
handler(1) <= "ZZZZZZZZ";
handler(2) <= "ZZZZZZZZ";
elsif clk = '1' and execute = '0' then
address <= pointer;
s_pointer <= pointer + 1;
if state = 1 then
instruction <= '0';
handler(0) <= ibus;
handler(1) <= "ZZZZZZZZ";
handler(2) <= "ZZZZZZZZ";
if (ibus(0 to 2) = "101" or ibus(0 to 2) = "110") then
test <= 1;
s_state <= 2;
elsif ibus(0 to 2) = "111" then
--test <= 2;
s_state <= 2;
s_read3 <= '1';
elsif (ibus(0) = '0' or ibus(0 to 2) = "100") then
test <= 3;
s_execute <= '1';
end if;
elsif state = 2 then
handler(1) <= ibus;
if read3 = '1' then
s_state <= 3;
s_read3 <= '0';
elsif read3 = '0' then
s_state <= 1;
s_execute <= '1';
end if;
elsif state = 3 then
handler(2) <= ibus;
s_state <= 1;
s_execute <= '1';
end if;
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
---
--- Execution phase
---
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
elsif clk = '1' and execute = '1' then
--not yet implemented
s_execute <= '0';
end if;
end process;
end Behavioral;
两个模块都链接在这个顶级模块中:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity microprocessor is
Port(
clk: IN std_logic;
rst: IN std_logic
);
end microprocessor;
architecture Behavioral of microprocessor is
component memory is
Port(
clk: IN std_logic;
instruction: IN std_logic;
address : IN std_logic_vector(0 to 15);
obus: OUT std_logic_vector(0 to 7);
ibus: IN std_logic_vector(0 to 7)
);
end component;
component cpu is
Port(
clk: IN std_logic;
rst: IN std_logic;
instruction: OUT std_logic;
address : OUT std_logic_vector(0 to 15);
obus: OUT std_logic_vector(0 to 7);
ibus: IN std_logic_vector(0 to 7)
);
end component;
signal address: std_logic_vector(0 to 15);
signal ctrbus: std_logic_vector(0 to 7);
signal rtcbus: std_logic_vector(0 to 7);
signal instruction: std_logic;
begin
memory1: memory port map (
clk => clk,
instruction => instruction,
address => address,
ibus => ctrbus,
obus => rtcbus
);
cpu1: cpu port map (
clk => clk,
rst => rst,
instruction => instruction,
address => address,
ibus => rtcbus,
obus => ctrbus
);
end Behavioral;
好的,我知道代码很多,但我非常感谢任何帮助。
所以,我的问题是,在模拟时,在第 5 个时钟周期,奇怪的事情发生了。在那一刻,RAM 将“11100111”放到它的 obus 上,所以 CPU 在这里:
if state = 1 then
instruction <= '0';
handler(0) <= ibus;
handler(1) <= "ZZZZZZZZ";
handler(2) <= "ZZZZZZZZ";
if (ibus(0 to 2) = "101" or ibus(0 to 2) = "110") then
test <= 1;
s_state <= 2;
elsif ibus(0 to 2) = "111" then <<<===== HERE
--test <= 2;
s_state <= 2;
s_read3 <= '1';
elsif (ibus(0) = '0' or ibus(0 to 2) = "100") then
test <= 3;
s_execute <= '1';
end if;
这在模拟中是有效的,因为 s_state 和 s_read3 都得到了各自的值。然而,最后一个条件不知为何也被执行了,因为 s_execute 也变成了 '1'!我不明白这怎么可能,这怎么可能
ibus(0 to 2) = "111"
还有这个
(ibus(0) = '0' or ibus(0 to 2) = "100")
同时是真的吗?
非常感谢,
雷戈克
此处代码过多,但有一些一般性的注释:
- 当
clk
为高电平时,您的主进程应该是透明的,否则锁存。但是,当 execute
上有一个 metaval 时,它不起作用。将其重构为具有单个外部 if clk='1'
,就像您的从属进程
- 您的主进程中的重置是可疑的。它只清除一个信号,不影响其他所有信号。所以,你有一个复杂的多功能闩锁。再想一想:重置所有信号,或者(更好)将重置移动到外部
if clk='1'
内部,或者(甚至更好)将重置明确实现为闩锁进程外部的 AND
门。保持闩锁尽可能简单。
- 使用
(others => '0')
等,而不是 0
/Z
的长列表
- 去掉
std_logic_arith
/std_logic_unsigned
。第一眼,
你甚至不需要它们。如果您确实需要它们,请始终使用
numeric_std
相反,除非你有充分的理由不
关于您的具体问题:这 2 个条件不能同时为真,但也不必同时为真。发生的事情是 ibus
正在改变其状态,而 clk
是 1
。当它有一个值时,您的代码设置 s_state
和 s_read3
;当它有另一个值时,它设置 s_execute
。其他信号保持不变,因为您没有分配给它们。
您没有分配 ibus
,因此您需要找出它发生变化的原因。你应该把它锁在你的从属进程中吗?
您可能还应该返回并确认在通过主进程的任何路径中未明确更改的任何信号实际上最终都具有正确的值。你的主代码是可疑的,如果只是因为你不明显 ibus
可能会改变并有效地锁存一些信号,即使它们在 clk
是 1
时是透明的.您可能需要重新设计:清除 all 您的主输出作为外部 if clk='1'
之后的第一个操作,然后分配给 all 输出,无论输入的当前状态如何。
我必须设计一个带有 RAM 的小型 CPU,但我遇到了一个我无法处理的问题。首先,我的代码:
这是内存
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity memory is
Port(
clk: IN std_logic;
instruction: IN std_logic;
address : IN std_logic_vector(0 to 15);
ibus: IN std_logic_vector(0 to 7);
obus: OUT std_logic_vector(0 to 7)
);
end memory;
architecture Behavioral of memory is
type memArr is array (integer range <> ) of std_logic_vector(0 to 7);
signal mem: memArr (0 to 65535);
signal rom: memArr (0 to 128);
signal ram: memArr (0 to 65407);
begin
-- LOAD/STORE Test
rom(0) <= "10100110"; -- step 1: (constant) load data1 into reg_addr1
rom(1) <= "00000000"; -- this one/
rom(2) <= "11100111"; -- step 2: (direct) load data2 from following address into reg_addr2
rom(3) <= "00000000"; -- this address
rom(4) <= "01000000"; -- contains data2/
rom(5) <= "10100000"; -- step 3: (constant) load followig data into reg_1
rom(6) <= "01010101"; -- this one/
rom(7) <= "10001000"; -- step 4: (indirect) store data in reg_1 to adress in reg_addr 1 + 2/
rom(64) <= "00000000"; -- data2 from step 2
mem(0 to 128) <= rom;
reading: process (clk, instruction, address)
begin
if clk ='1' and instruction = '0' then
obus <= mem(conv_integer(unsigned(address)));
end if;
end process;
writing: process (clk, instruction, address, ibus)
begin
if clk ='1' and instruction = '1' then
ram(conv_integer(unsigned(address))) <= ibus;
end if;
end process;
end Behavioral;
这是CPU:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity cpu is
Port(
clk: IN std_logic;
rst: IN std_logic;
instruction: OUT std_logic;
address : OUT std_logic_vector(0 to 15);
obus: OUT std_logic_vector(0 to 7);
ibus: IN std_logic_vector(0 to 7)
);
end cpu;
architecture Behavioral of cpu is
--signal reg_1, reg_2, reg_3, reg_4, reg_5, reg_acc, reg_addr1, reg_addr2: std_logic_vector(0 to 7);
signal pointer, s_pointer: std_logic_vector(0 to 15);
signal state, s_state, test: integer range 0 to 3;
signal read3, s_read3, execute, s_execute: std_logic;
type reg is array (integer range <>) of std_logic_vector(0 to 7);
signal registers: reg (0 to 7);
signal handler: reg (0 to 2);
begin
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
---
--- Slave process (runs at '0')
---
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
slave: process (clk, s_pointer, s_state, s_read3, s_execute)
begin
if clk = '0' then
pointer <= s_pointer;
state <= s_state;
read3 <= s_read3;
execute <= s_execute;
end if;
end process;
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
---
--- Master process (runs at '1')
---
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
master: process (clk, rst, ibus, pointer, state, read3, execute)
begin
if rst = '1' then
s_state <= 0;
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
---
--- FSM to read instructions
---
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
elsif clk = '1' and state = 0 then
s_state <= 1;
s_pointer <= "0000000000000000";
address <= "0000000000000000";
s_read3 <= '0';
s_execute <= '0';
instruction <= '0';
handler(0) <= "ZZZZZZZZ";
handler(1) <= "ZZZZZZZZ";
handler(2) <= "ZZZZZZZZ";
elsif clk = '1' and execute = '0' then
address <= pointer;
s_pointer <= pointer + 1;
if state = 1 then
instruction <= '0';
handler(0) <= ibus;
handler(1) <= "ZZZZZZZZ";
handler(2) <= "ZZZZZZZZ";
if (ibus(0 to 2) = "101" or ibus(0 to 2) = "110") then
test <= 1;
s_state <= 2;
elsif ibus(0 to 2) = "111" then
--test <= 2;
s_state <= 2;
s_read3 <= '1';
elsif (ibus(0) = '0' or ibus(0 to 2) = "100") then
test <= 3;
s_execute <= '1';
end if;
elsif state = 2 then
handler(1) <= ibus;
if read3 = '1' then
s_state <= 3;
s_read3 <= '0';
elsif read3 = '0' then
s_state <= 1;
s_execute <= '1';
end if;
elsif state = 3 then
handler(2) <= ibus;
s_state <= 1;
s_execute <= '1';
end if;
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
---
--- Execution phase
---
---HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH---
elsif clk = '1' and execute = '1' then
--not yet implemented
s_execute <= '0';
end if;
end process;
end Behavioral;
两个模块都链接在这个顶级模块中:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity microprocessor is
Port(
clk: IN std_logic;
rst: IN std_logic
);
end microprocessor;
architecture Behavioral of microprocessor is
component memory is
Port(
clk: IN std_logic;
instruction: IN std_logic;
address : IN std_logic_vector(0 to 15);
obus: OUT std_logic_vector(0 to 7);
ibus: IN std_logic_vector(0 to 7)
);
end component;
component cpu is
Port(
clk: IN std_logic;
rst: IN std_logic;
instruction: OUT std_logic;
address : OUT std_logic_vector(0 to 15);
obus: OUT std_logic_vector(0 to 7);
ibus: IN std_logic_vector(0 to 7)
);
end component;
signal address: std_logic_vector(0 to 15);
signal ctrbus: std_logic_vector(0 to 7);
signal rtcbus: std_logic_vector(0 to 7);
signal instruction: std_logic;
begin
memory1: memory port map (
clk => clk,
instruction => instruction,
address => address,
ibus => ctrbus,
obus => rtcbus
);
cpu1: cpu port map (
clk => clk,
rst => rst,
instruction => instruction,
address => address,
ibus => rtcbus,
obus => ctrbus
);
end Behavioral;
好的,我知道代码很多,但我非常感谢任何帮助。 所以,我的问题是,在模拟时,在第 5 个时钟周期,奇怪的事情发生了。在那一刻,RAM 将“11100111”放到它的 obus 上,所以 CPU 在这里:
if state = 1 then
instruction <= '0';
handler(0) <= ibus;
handler(1) <= "ZZZZZZZZ";
handler(2) <= "ZZZZZZZZ";
if (ibus(0 to 2) = "101" or ibus(0 to 2) = "110") then
test <= 1;
s_state <= 2;
elsif ibus(0 to 2) = "111" then <<<===== HERE
--test <= 2;
s_state <= 2;
s_read3 <= '1';
elsif (ibus(0) = '0' or ibus(0 to 2) = "100") then
test <= 3;
s_execute <= '1';
end if;
这在模拟中是有效的,因为 s_state 和 s_read3 都得到了各自的值。然而,最后一个条件不知为何也被执行了,因为 s_execute 也变成了 '1'!我不明白这怎么可能,这怎么可能
ibus(0 to 2) = "111"
还有这个
(ibus(0) = '0' or ibus(0 to 2) = "100")
同时是真的吗?
非常感谢, 雷戈克
此处代码过多,但有一些一般性的注释:
- 当
clk
为高电平时,您的主进程应该是透明的,否则锁存。但是,当execute
上有一个 metaval 时,它不起作用。将其重构为具有单个外部if clk='1'
,就像您的从属进程 - 您的主进程中的重置是可疑的。它只清除一个信号,不影响其他所有信号。所以,你有一个复杂的多功能闩锁。再想一想:重置所有信号,或者(更好)将重置移动到外部
if clk='1'
内部,或者(甚至更好)将重置明确实现为闩锁进程外部的AND
门。保持闩锁尽可能简单。 - 使用
(others => '0')
等,而不是0
/Z
的长列表
- 去掉
std_logic_arith
/std_logic_unsigned
。第一眼, 你甚至不需要它们。如果您确实需要它们,请始终使用numeric_std
相反,除非你有充分的理由不
关于您的具体问题:这 2 个条件不能同时为真,但也不必同时为真。发生的事情是 ibus
正在改变其状态,而 clk
是 1
。当它有一个值时,您的代码设置 s_state
和 s_read3
;当它有另一个值时,它设置 s_execute
。其他信号保持不变,因为您没有分配给它们。
您没有分配 ibus
,因此您需要找出它发生变化的原因。你应该把它锁在你的从属进程中吗?
您可能还应该返回并确认在通过主进程的任何路径中未明确更改的任何信号实际上最终都具有正确的值。你的主代码是可疑的,如果只是因为你不明显 ibus
可能会改变并有效地锁存一些信号,即使它们在 clk
是 1
时是透明的.您可能需要重新设计:清除 all 您的主输出作为外部 if clk='1'
之后的第一个操作,然后分配给 all 输出,无论输入的当前状态如何。