【问题标题】:How to run VHDL Components in a sequential fashion?如何以顺序方式运行 VHDL 组件?
【发布时间】:2014-02-25 16:55:01
【问题描述】:

我正在用 VHDL 制作一个简单的井字游戏(计算机与用户),代码几乎完成了,但有些东西我不知道如何处理它。

总共有三个主要模块,基于当前网格的计算机移动,网格状态,由计算机或用户填充哪个单元格,一个从网格模块检索网格并处理这些组件的主模块以及用户的移动。

所以,在这个主模块中,我有一个组件将移动(通过计算机或用户)发送到网格模块,并在此主模块中更新其当前网格信号,然后是第二个组件(计算机移动)接受网格状态(即信号)并据此采取行动。因此,这也需要发送到网格模块以进行更新。但是,当涉及到按此顺序运行时,这并没有真正起作用。

简而言之,我的问题是,我如何才能按照组件执行的顺序更新这个主信号,或者更一般地说,我如何让一个需要成为另一个输入的组件更新一个信号分别是组件?

感谢您的帮助。

编辑

这里是部分主模块代码

ENTITY currentstate IS
  PORT (to_occupy_cell : IN TO_SELECT;   --user choice
        start : IN STD_LOGIC;     --initialize the grid
        by_user : IN STD_LOGIC;   --how to fill the grid (X or O)
        difficulty : IN STD_LOGIC;     --difficulty
        winner_state : OUT INTEGER RANGE 0 to 2;     --who is the winner? 
        currentgrid : OUT GRID (1 TO 3, 1 TO 3));  --outputs status of the grid after compmove to be displayed
END currentstate;
---------------------------------
ARCHITECTURE statearch OF currentstate IS
  SIGNAL comp_occupy : TO_SELECT;
  SIGNAL grid_status : GRID (1 TO 3, 1 TO 3);

  COMPONENT grid IS   -------saves the grid status
    PORT (to_occupy_cell : IN TO_SELECT; start : IN STD_LOGIC; by_user : IN STD_LOGIC; currentgrid : OUT GRID (1 TO 3, 1 TO 3));
  END COMPONENT;

  COMPONENT compmove IS
    PORT (current : IN GRID (1 TO 3, 1 TO 3); dif : IN STD_LOGIC; compsel : OUT TO_SELECT);
  END COMPONENT;
BEGIN

  U1: grid PORT MAP (to_occupy_cell, start, by_user ,grid_status);

  U2: compmove PORT MAP (grid_status, difficulty, comp_occupy); 

这里是网格模块

ENTITY grid IS
  PORT (to_occupy_cell : IN TO_SELECT;   --user choice
        start : IN STD_LOGIC;     --initialize the grid
        by_user : IN STD_LOGIC;   --how to fill the grid ( X or O)
        currentgrid : OUT GRID (1 TO 3, 1 TO 3));  --outputs status of the grid after compmove to be displayed
END grid;
---------------------------------
ARCHITECTURE gridstatus OF grid IS
BEGIN
    PROCESS (to_occupy_cell, start)
    VARIABLE temp_grid : GRID (1 TO 3, 1 TO 3);
  BEGIN
    IF (start = '1' AND start'EVENT) THEN
      temp_grid := (others => (others=>0));
    END IF;
    IF (by_user = '1') THEN 
      temp_grid(to_occupy_cell(0), to_occupy_cell(1)) := 1; 
    ELSIF (by_user = '0') THEN 
      temp_grid(to_occupy_cell(0), to_occupy_cell(1)) := 2;
    END IF;

    currentgrid <= temp_grid;
  END PROCESS;
END gridstatus;

计算机实体移动模块

---------------------------------
ENTITY compmove IS
  PORT(current : IN GRID (1 TO 3, 1 TO 3);  --takes in the grid status
       dif : IN STD_LOGIC;     --difficulty
       compsel : OUT TO_SELECT);
END compmove;
---------------------------------

所以,发生的情况是,信号 grid_status 应该首先由用户移动自动更新,然后当它更新时,它会通过管道传输到 compmove 模块,以便计算机决定填充哪个单元格。之后,grid_status 应该再次更新。另外,“1”是用户移动,“2”是计算机在网格中移动。

希望这能清除我所追求的。

(添加了来自link的图片)

编辑 2:

感谢 David 和 fru1tbat 的帮助,我实际上可以让它工作了!原来我错过了让 compmove 对 grid_status 敏感。 但是,如果用户选择另一个单元格,现在它只适用于第一轮而不是第二轮。以下是更新后的代码:

主模块(当前状态)

ENTITY currentstate IS
  PORT (to_occupy_cell : IN TO_SELECT;   --user choice
        start : IN STD_LOGIC;     --initialize the grid
        by_user : IN STD_LOGIC;   --how to fill the grid ( X or O)
        difficulty : IN STD_LOGIC;     --difficulty
        winner_state : OUT INTEGER RANGE 0 to 2);     --who is the winner? 
END currentstate;
---------------------------------
ARCHITECTURE statearch OF currentstate IS
  SIGNAL occupy_to_grid : TO_SELECT;
  SIGNAL comp_occupy : TO_SELECT;
  SIGNAL user_move : STD_LOGIC;
  SIGNAL grid_status : GRID (1 TO 3, 1 TO 3);

  COMPONENT grid_ IS   -------saves the grid status
    PORT (to_occupy_cell : IN TO_SELECT; start : IN STD_LOGIC; by_user : IN STD_LOGIC; currentgrid : OUT GRID (1 TO 3, 1 TO 3));
  END COMPONENT;

  COMPONENT compmove IS
    PORT (current : IN GRID (1 TO 3, 1 TO 3); by_user : IN STD_LOGIC; dif : IN STD_LOGIC; compsel : OUT TO_SELECT);
  END COMPONENT;

BEGIN

  U1: grid_ PORT MAP (occupy_to_grid, start, user_move,grid_status);

  U2: compmove PORT MAP (grid_status, user_move, difficulty, comp_occupy); 

  PROCESS(comp_occupy, to_occupy_cell)
  BEGIN
    IF to_occupy_cell'EVENT THEN
      occupy_to_grid <= to_occupy_cell;
      user_move <= by_user;
    END IF;
    IF comp_occupy'EVENT THEN
      occupy_to_grid <= comp_occupy;
      user_move <= '0';
    END IF;
  END PROCESS;
END statearch;

grid_ 模块

ENTITY grid_ IS
  PORT (to_occupy_cell : IN TO_SELECT;   --user choice
        start : IN STD_LOGIC;     --initialize the grid
        by_user : IN STD_LOGIC;   --how to fill the grid ( X or O)
        currentgrid : OUT GRID (1 TO 3, 1 TO 3));  --outputs status of the grid after compmove to be displayed
END grid_;
---------------------------------
ARCHITECTURE gridstatus OF grid_ IS
BEGIN
    PROCESS (to_occupy_cell, start)
    VARIABLE temp_grid : GRID (1 TO 3, 1 TO 3);
  BEGIN
    IF (start = '1' AND start'EVENT) THEN
      temp_grid := (others => (others=>0));
    END IF;
    IF (by_user = '1') THEN 
      temp_grid(to_occupy_cell(0), to_occupy_cell(1)) := 1; 
    ELSIF (by_user = '0') THEN 
      temp_grid(to_occupy_cell(0), to_occupy_cell(1)) := 2;
    END IF;

    currentgrid <= temp_grid;
  END PROCESS;
END gridstatus;

compmove 的初始部分

ENTITY compmove IS
  PORT(current : IN GRID (1 TO 3, 1 TO 3);  --takes in the grid status
       by_user : IN STD_LOGIC;   --to only gets triggered when user selects a cell
       dif : IN STD_LOGIC;     --difficulty
       compsel : OUT TO_SELECT);
END compmove;
---------------------------------
ARCHITECTURE comparch OF compmove IS  
BEGIN

  PROCESS(by_user, current)
    VARIABLE tempsel : TO_SELECT := (0,0);
    VARIABLE occ_count : INTEGER := 0;
    VARIABLE unocc : INTEGER := 0;
  BEGIN
    IF (dif = '0' AND current'EVENT AND by_user = '1') THEN
      --------------bunch of codes here

它几乎就在那里,我相信 compmove 的敏感列表中的一个小改动可能会让它相应地检索更新的 grid_status ,因为目前在第一轮之后它不会接受更新的 grid_status 和comp_occupy 保持不变!

【问题讨论】:

  • 很难理解你在问什么。如果可能的话,您是否认为您可以提供一张硬件图,注明有问题的信号以及一些相关声明?
  • 好的,用更多信息更新了帖子。
  • 恐怕我还是不太清楚你在问什么,我可以问你一张图表吗? (如果您试图将两个信号合并到一个输入中,则必须先合并这两个信号......例如或将它们合并在一起)
  • 感谢您的回复!这有意义吗? link
  • 您的实体/架构对当前的编写方式看起来像是他们保证currentgrid 是原子写入、接收的。它们将被一个增量周期分开。在不了解compmove 的情况下,difficulty 上的并发事件是否可能导致您的问题?当然,另一种可能性是您在某处出现错误(例如compmove)。

标签: components vhdl sequential


【解决方案1】:

您似乎在网格中的进程敏感度列表中缺少by_user

process (to_occupy_cell, start)      -- Add by_user to sensitivity list
    variable temp_grid : grid (1 to 3, 1 to 3);
begin
    if (start = '1' and start'event) then
        temp_grid := (others => (others=>0));
    end if;

    if (by_user = '1') then 
        temp_grid(to_occupy_cell(0), to_occupy_cell(1)) := 1; 
    elsif (by_user = '0') then 
        temp_grid(to_occupy_cell(0), to_occupy_cell(1)) := 2;
    end if;

    currentgrid <= temp_grid;
end process;

唯一符合您描述的是缺少事件触发该过程。 by_user 的想法与任何其他输入都不并发。

我还发现currentstate 中组件声明中的grid 与包含grid 类型声明的未声明包之间存在名称冲突,其中包含两个不同的VHDL 分析器。 (在为to_selectgrid 编写包和类型声明之后)。

附录

我添加了一个测试台,并将grid_status 连接到currentstate 中返回的currentgrid,因此它会显示在顶层。

library ieee;
use ieee.std_logic_1164.all;
use work.foobat.all;

entity  test is
end entity;

architecture foo of test is

    component currentstate is
        port (
            to_occupy_cell: in      to_select;   --user choice
            start:          in      std_logic;     --initialize the grid
            by_user:        in      std_logic;   --how to fill the grid (x or o)
            difficulty:     in      std_logic;     --difficulty
            winner_state:   out     integer range 0 to 2;  --who is the winner? 
            currentgrid:    out     grid (1 to 3, 1 to 3)
        );  --outputs status of the grid after compmove to be displayed
    end component;


    signal to_occupy_cell:  to_select;
    signal start:           std_logic := '0';
    signal by_user:         std_logic := '1'; 
    signal difficulty:      std_logic := '0'; 
    signal winner_state:    integer range 0 to 2;
    signal currentgrid:     grid(1 to 3, 1 to 3);

begin

DUT:
    currentstate
        port map (
            to_occupy_cell => to_occupy_cell,
            start          =>  start,
            by_user        =>  by_user,
            difficulty     =>  difficulty,
            winner_state   =>  winner_state,
            currentgrid    =>  currentgrid     -- grid_status
        );

STIMULUS:
    process
    begin
        wait for 1 sec;
        to_occupy_cell <= (2,2);    -- center
        start <= '1';               -- write 1 to gridstatus(2,2);
        wait for 1 sec;
        to_occupy_cell <= (1,1);    -- corner
        start <= '0';               -- no separate delta cycle event
        wait for 1 sec;
        wait;

    end process;

end architecture;

所以下面显示的两组网格值是grid_status(浮出水面)和compmove端口上的current。据我所知,grid_status 变为 compmove

这是通过 ghdl 和 gtkwave 完成的。 ghdl 处理波形中的阵列信号。波形轨迹图像比浏览器中可能显示的要大,您可以在单独的选项卡/窗口中打开它或以其他方式查看更大的图像。

两个版本grid_status/current 显示的值相同。

注意grid_status 上有三个事件,初始事件写入网格中最左侧的行和列。我不确定为什么to_occupy_cell 没有正确显示在波形中,它没有显示为数组但确实显示了事件。这可能是我声明to_select 类型的结果。

初始或默认事务、start'event and start = '1' 事务和 to_occupy_cell 转换(与 start = 0 并发)。

不管怎样,重点是grid_status 会到达compmove

【讨论】:

  • 其实 by_user 是在 to_occupy_cell 发生变化的同时更新的,因为当用户选择要占用的单元格时 by_user 也会被它触发,因此,PROCESS 仍然应该由当前触发敏感列表,不是吗?哦,是的,抱歉,忽略 Grid 错字,当我想在这里粘贴代码时,我只是用另一个合理的名称替换了这个名称,但是你注意到它与 Grid 类型冲突。如图所示,我想要实现的目标是否可行?
  • 好吧,如果不涉及超过 20 个问题,如果没有更多描述,您不可能在这里得到答案,无论是实际发生的事情(不仅仅是没有发生的事情)或超过 1 个/3 您的设计说明。如果没有看到包含 current_state 的设计规范,或者您没有显示波形,那么您遇到的问题并不明显。
  • 这是这里的所有代码,除了我高度怀疑它是有问题的compmove(我也让它对by_user敏感)。问题/问题都与第一篇文章中的那个单一图表有关!假设初始化时grid_status 为0,grid 组件的输出会改变grid_status 的值假设为1。同时grid_status 是compmove 组件的输入,但是compmove 接收到的是0 而不是1!这就是我所追求的,我希望 compmove 组件检索更新的 grid_status。如果我把所有的代码都发给你会有帮助吗? :S
  • 见答案中的附录
  • 非常感谢您的详尽解释,正如您之前所说,compmove 敏感度列表中确实存在问题,我以某种方式修复了它,但是,它现在只适用于第一轮!更新了第一篇文章。
【解决方案2】:

您写入grid_status 信号的进程只接受来自用户的输入(comp_occupy 不连接到您的主模块中的任何内容)那么计算机如何通过移动来更新网格?您似乎需要的是连接到comp_occupygrid 模块的输入(或一组输入),以及gridstatus 中的一个修改过程,该过程监视两个玩家并从任一源更新网格。

(编辑)

进一步考虑,我意识到您的意图可能是对grid 模块进行单个输入,从而为任一玩家添加移动。您似乎想使用by_user 上的事件来更新网格,但我看不到切换by_user 以创建序列的逻辑。您似乎需要类似的东西(在您的主要组件中):

process (to_occupy_cell, comp_occupy)
begin
  if by_user = '1' then
    occupy_to_grid <= to_occupy_grid;
  else
    occupy_to_grid <= comp_occupy;
  end if;
  by_user <= not by_user; -- on input from either source, alternate user for next input
end process;

然后将occupy_to_grid 映射到grid 而不是to_occupy_cell。这假设两个 'occupy' 信号的新值都分配在同一个增量上(否则by_user 会意外地来回翻转),因此如果不是这种情况,则需要相应地进行修改。

如果这与您正在寻找的内容接近,请告诉我。

【讨论】:

  • 好建议!它真的很有帮助。尽管如此,仍然有一个小问题,我更新了第一篇文章。您是否介意看一下它,并找出哪个部分功能不正常,它不适用于第二轮。
  • 这将有助于查看您的激励/测试平台,可能还有您的compmove 代码。我运行了一个快速模拟,它运行良好。请注意,如果 AI 移动到 (0, 0),则不会触发更新,因为这可能是 compsel 的初始值,因此不会生成信号事件(可能与玩家相同)。您可能想要添加另一个(二进制?)信号,明确告诉算法已经发出了移动。
  • 嗯,想知道为什么它对我不起作用,compmove 代码很长很简单,只做决策,最后它将 move 应用于 compsel 信号。我有一些感觉 IF 语句条件不是真的正确。为了测试它,首先我设置 Start = 1,dif = 0,进行一次运行,然后在 to_occupy_cell 中指定一个单元格并设置 by_user = 1,这对于第一次运行很好。之后,我只更改 to_occupy_cell 并期望它在另一次运行后工作(或者我应该自己更改 by_user 吗?)。幸运的是,网格从 (1,1) 开始,因此 (0,0) 的值无论如何都是无效的!
  • 抱歉 - 忘记了您的网格范围是 1 到 3。然后,这取决于您如何定义 TO_SELECT 类型。如果您使用范围限制为(1 到 3)的整数子类型,您将遇到同样的问题。只要TO_SELECT 类型的信号没有初始化为有效的网格位置,就可以了。
  • TO_SELECT 是这样的:TYPE to_select IS ARRAY (0 to 1) OF INTEGER RANGE 0 TO 3;所以,我相信这也不成问题。我现在无法发现错误可能在哪里:(
猜你喜欢
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
  • 2020-03-08
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2020-07-26
相关资源
最近更新 更多