2

私はVHDLを学んでおり、プロジェクトを含めるよりも学ぶのに良い方法があります。したがって、私のプロジェクトの一部は、小さなメモリコンポーネントを作成することです。

これが私の完全なコードです:

entity memory is
  port(
    Address: in std_logic_vector(15 downto 0); --memory address
    Write: in std_logic; --write or read
    UseTopBits: in std_logic;  --if 1, top 8 bits of data is ignored and not written to memory
    Clock: in std_logic;
    DataIn: in std_logic_vector(15 downto 0);
    DataOut: out std_logic_vector(15 downto 0);
    Reset: in std_logic
  );
end memory;

architecture Behavioral of memory is
  constant SIZE : integer := 4096;
  type memorytype is array(0 to (size-1)) of std_logic_vector(7 downto 0);
  signal mem: memorytype;

begin
  resetmem: process(Clock, Reset) --this process is the troublemaker 
  begin
  if(Reset ='1' and rising_edge(Clock)) then
    mem <= (others => "00000000");
  end if;

  end process;
  writemem: process(Reset,Write, Address, UseTopBits, Clock)
    variable addr: integer;
  begin
    addr := conv_integer(Address);
    if(addr>size-1) then
      addr:=0;
    end if;
    if(Write='1' and Reset='0') then
      if(rising_edge(clock)) then
        mem(conv_integer(addr)) <= DataIn(7 downto 0);
        if(UseTopBits='1') then
          mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
        end if;
      end if;
    end if;
  end process;
  readmem: process(Reset,Address,Write,Clock)
    variable addr: integer;
  begin
    addr := conv_integer(Address);
    if(addr>size-1) then
      addr:=0;
    end if;
    if(Reset='1') then
      DataOut <= (others => '0');
    elsif(Write='0') then
      DataOut <= mem(conv_integer(addr)+1) & mem(conv_integer(addr));
    else 
      DataOut <= (others => '0');
    end if;
  end process;
end Behavioral;

リセットプロセスを追加する前は、テストベンチに従ってコードは正常に機能していました。今それを追加した後、私はにあらゆる種類の奇妙さを得るDataOut。一見ランダムなビットは、またはのX代わりにの論理状態になり、これにより、すべてのテストベンチが失敗します(そうあるべきです)01

writemem次のようにコードをプロセスに入れることで修正しました。

begin
  --where resetmem process was
  writemem: process(Reset,Write, Address, UseTopBits, Clock)
    variable addr: integer;
  begin
    addr := conv_integer(Address);
    if(addr>size-1) then
      addr:=0;
    end if;
    if(Reset ='1' and rising_edge(Clock)) then --code is now here
      mem <= (others => "00000000");
    elsif(Write='1' and Reset='0') then
      if(rising_edge(clock)) then
        mem(conv_integer(addr)) <= DataIn(7 downto 0);
        if(UseTopBits='1') then
          mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
        end if;
      end if;
    end if;
  end process;

そのため、この問題は現在修正されていますが、resetmemを別のプロセスとして使用すると、これらの奇妙な問題がすべて発生した理由がわかりません。誰かがこれがどのように起こったかについていくつかの光を当てることができますか?

4

2 に答える 2

2

mem異なる(非Z)値で同時に駆動する2つのプロセスがあります。これが、「X」値の原因です。

また、コードの合成を計画している場合は、フリップフロップを推測するための推奨プロセステンプレートを確認することをお勧めします(ザイリンクスISEを使用している場合は、[編集]>[言語テンプレート]>[VHDL]>[合成構造]にあります。 >コーディング例>フリップフロップ)。これにより、リセット/クロックイネーブルピンの優先順位を正しく設定し、FPGAハードウェアに効率的にマッピングするデザインを取得できます。

例えば:

if(Write='1' and Reset='0') then
  if(rising_edge(clock)) then
    mem(conv_integer(addr)) <= DataIn(7 downto 0);
    if(UseTopBits='1') then
      mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
    end if;
  end if;
end if;

シンセサイザーのインテリジェンスによっては、これによりクロックイネーブル(Write)がFPGAに実際に存在するよりも「高い」優先度になる可能性があります。また、後でコードを追加すると、これが発生するリスクが高くなります。もちろん。

あなたがそれを次のように書く場合:

if(Reset='1') then
  --Do nothing, for now
elsif(rising_edge(clock)) then
  if(Write='1') then
    mem(conv_integer(addr)) <= DataIn(7 downto 0);
    if(UseTopBits='1') then
      mem(conv_integer(addr)+1) <= DataIn(15 downto 8);
    end if;
  end if;
end if;

コードははるかにクリーンになり、基盤となるハードウェアに対してもはるかに優れた合成が可能になります(少なくともザイリンクスFPGAの場合)。

また、KenChapmansをご覧ください。優先順位を正しく理解するためのホワイトペーパー。

于 2012-04-30T09:05:33.843 に答える
2

VHDLには、シグナルの「ドライバー」というこの概念があります。

信号(またはバスの場合はその一部)に書き込む各プロセスは、ドライバーを作成します。複数のドライバーが信号に接続されている場合、「解決関数」が呼び出され、結果の値を決定します。(最初の近似では)のstd_logic(したがってstd_logic_vectorsビットの)解決関数は、反対の値(1および0)を持つドライバーが信号に駆動されるときにXを生成することがあります。Z他の値で上書きできる非駆動値として扱われるという値もあります。(、、、がありますが、W今のところ、初期化されていないため、それらは脇に置いておきます)LHU

このプロセス:

resetmem: process(Clock, Reset) --this process is the troublemaker 
  begin
  if(Reset ='1' and rising_edge(Clock)) then
    mem <= (others => "00000000");
  end if;
end process;

言う(言い換えれば)

if(リセットおよびクロック)その後、ゼロをmemに駆動します

条件がfalseの場合の対処方法については何も述べていないため、(残りの時間は)ゼロを駆動し続けます。他のプロセスが値を駆動すると、それらは衝突してXsを生成します

シミュレーションの目的で、次のことができます

else
  mem <= (others => 'Z');

これにより、他のプロセスがオーバーライドできるハイインピーダンスが「駆動」されます。


ただし、あなたがやろうとしているのは、RAMをすべてゼロに初期化することだと思います。FPGA RAMは、特定の値への信号でリセットすることはできませんが、構成時に値をロードすることはできます。シミュレーターは構成プロセスについて何も知りません。シミュレーションは構成が完了した後に行われていると見なされます。

したがって、この動作をシミュレートする1​​つの方法は、宣言時にシグナルを初期化することです。

signal mem: memorytype := (others => (others => '0'));
于 2012-04-30T09:54:15.267 に答える