如何以顺序方式运行VHDL组件?

时间:2014-02-25 16:55:01

标签: components vhdl sequential

我正在用VHDL制作一个简单的TicTacToe游戏(计算机与用户)并且代码几乎已经完成,但有些东西我无法弄清楚如何处理它。

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

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

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

感谢您的帮助。

修改

这是主模块代码的一部分

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引用的图片添加)

sequential components

编辑2:

感谢大卫和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_ module

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保持不变!

2 个答案:

答案 0 :(得分:2)

您似乎在网格中的过程敏感度列表中缺少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的想法不与任何其他输入同时发生。

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

附录

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

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端口上的current(浮出水面)和compmove。据我所知,grid_status到达compmove

grid_status gets to 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

答案 1 :(得分:1)

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

(适用编辑)

进一步考虑后,我意识到你的意图可能是为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。这假设两个'占用'信号的新值都在同一个delta上分配(否则to_occupy_cell会意外地来回翻转),所以如果不是这样,你需要相应修改。

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