【问题标题】:VHDL latch issues (flip-flops are not an option)VHDL 锁存器问题(触发器不是一个选项)
【发布时间】:2015-11-12 21:22:18
【问题描述】:

我必须设计一个带有 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 = '1'rising_edge(clk) 之间的区别,并在继续之前将整个代码重写为正确的时钟进程。
  • 感谢您的回答,但这些进程不是触发器,它们是锁存器,它们应该在没有上升沿(clk)的情况下工作。这是老师给的前提。
  • 这是一个奇怪的约束,以至于问题可能有用地提到您特别想要闩锁。所以,你是靠自己的。嫌疑人在唤醒过程中出现故障,或敏感度列表错误。在每个分支中添加断言,以准确了解发生了什么以及何时发生。并理解为什么每一个都会触发。你必须自己调试它。哦,练习的目的可能是加强时钟进程的优点......
  • 我已经尝试了好几个小时,通过检查每个分支的信号并了解发生的情况和时间来自己调试它。但我想不通,这就是我来这里的原因。这当然不是练习的目的,因为这是我们整个学期唯一的练习。整个课程就是这个项目。
  • 您的设计似乎证明了为什么某些设计使用多相(非重叠)时钟,允许使用锁存器而不是寄存器(更少的门)。连续阶段更新和评估,而不传播基于组合延迟的不适当事件(故障)。永远不要在同一时钟相位将表达式评估为锁存输入,它的任何输入都被锁存。这可能需要增加状态数、用于转换时钟相位的锁存器或使用两个以上的时钟相位。

标签: vhdl


【解决方案1】:

这里的代码太多了,但是一些通用的cmets:

  • clk 为高电平时,您的主进程应该是透明的,否则为闩锁。但是,当execute 上有一个元数据时,它就不起作用了。将其重构为具有单个外部 if clk='1',例如您的从属进程
  • 您的主进程中的重置是可疑的。它只清除一个信号,不影响其他所有信号。所以,你有一个复杂的多功能锁存器。再想一想:重置所有信号,或者(更好)将重置移动到外部if clk='1' 内,或者(甚至更好)将重置明确地实现为锁存过程之外的AND 门。保持闩锁尽可能简单。
  • 使用(others =&gt; '0')等,而不是0/Z的长列表
  • 摆脱std_logic_arith/std_logic_unsigned。第一眼, 你甚至不需要它们。如果您确实需要它们,请始终使用 numeric_std 而不是,除非你有充分的理由不这样做

关于您的具体问题:这两个条件不能同时为真,但不一定是。发生的事情是ibus 正在改变其状态,而clk1。当它有一个值时,您的代码设置s_states_read3;当它有另一个值时,它设置s_execute。其他信号保持不变,因为您没有分配给它们。

您没有分配ibus,因此您需要找出它发生变化的原因。你应该把它锁在你的从属进程中吗?

您可能还应该返回并确认在通过您的主进程的任何路径中未明确更改的任何信号实际上最终具有正确的值。你的主代码是可疑的,如果只是因为你并不明显ibus 可能会改变并有效地锁定一些信号,即使当clk1 时它们是透明的。您可能需要重新设计:清除 all 您的主输出作为外部 if clk='1' 之后的第一个操作,然后将输出分配给 all,无论当前状态如何的输入。

【讨论】:

  • 非常感谢!今天我问了我的老师,他告诉我问题实际上是ibus改变了,并且激活了latch。这是因为在主进程开始时,我更改了“地址”,这是通往 RAM 的总线。因此 RAM 通过 ibus 发送一个新值,因为它指向一个新地址。此外,执行位实际上是错误的,或者至少不是应该的,这个功能应该通过状态 4 来实现;这也将摆脱您提到的其他一些问题。无论如何,再次感谢,你帮助最多:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-17
  • 1970-01-01
相关资源
最近更新 更多