Перейти к содержанию
    

Сигнал в VHDL числового типа с ограничением сверху против Modelsim

Здравствуйте.

Начал осваивать ModelSim и натолкнулся на такие грабли.

Имеется следующий упрощенный код на VHDL, при компиляции его в Quartus 9.1 и последующей временной симуляции в Quartus все замечательно.

library ieee;
use ieee.std_logic_1164.all;

entity cnt is
  generic (
    constant CNT_MAX : positive := 5
  );
  port (
    rst : in std_logic;
    clk : in std_logic;
    ena : out std_logic
  );
end entity;
architecture arc of cnt is
  signal cnt : natural range 0 to CNT_MAX - 1;
begin  
  process (all)
  begin
    if (rst = '1') then
      cnt <= 0;
    elsif (rising_edge(clk)) then
      cnt <= cnt + 1;                   --- !!! ОШИБКА !!!
      if (cnt = CNT_MAX - 1) then
        cnt <= 0;
      end if;
    end if;
  end process;
  
  process (all)
  begin
    if (rst = '1') then
      ena <= '0';
    elsif (rising_edge(clk)) then
      if (cnt = CNT_MAX - 1) then
        ena <= '1';
      else
        ena <= '0';
      end if;
    end if;
  end process;  
end;

Но при функциональной симуляции в ModelSim выскакивает следующая ошибка:

# ** Fatal: (vsim-3421) Value 5 is out of range 0 to 4.

на строке с коментарием.

Я понимаю откуда она возникла. Вопрос в том, как ее обходить?

Предложения:

1. не использовать числовые типы, а только массивы битов;

2. задавать какие-нибудь атрибуты для симуляции;

3. не использовать такую манеру написания кода, а явно прописывать для данного примера изменение сигнала cnt по условию else условного оператора. Но тогда много придется править для случаев, в которых сигнал сбрасывается в определенных условиях оператора case.

Подскажите, как правильно поступить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. не использовать числовые типы, а только массивы битов;

Да.

2. задавать какие-нибудь атрибуты для симуляции;

Никакие атрибуты не помогут. Грубо говоря, выход за границы массива контролируется самим языком -- он не даёт вам прострелить себе ногу.

3. не использовать такую манеру написания кода, а явно прописывать для данного примера изменение сигнала cnt по условию else условного оператора.
В любом случае надо не допускать выхода за грницу массива. Поэтому сначала проверяем, а потом или сбрасываем счётчик, или делаем инкремент/декремент. Это, кстати, надо делать вне зависимости от того, целочисленный счётчик или битовый.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема как в типе, так и в логике работы.

 

    if (cnt= CNT_MAX- 1) then
        cnt<= 0;
    else
        cnt<= cnt+ 1;
   end if;

 

Если использовать тип unsigned, то переполнение не будет приводить к ошибке, и получится удобный счетчик по модуля 2^N

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Никакие атрибуты не помогут. Грубо говоря, выход за границы массива контролируется самим языком -- он не даёт вам прострелить себе ногу.

В любом случае надо не допускать выхода за грницу массива. Поэтому сначала проверяем, а потом или сбрасываем счётчик, или делаем инкремент/декремент. Это, кстати, надо делать вне зависимости от того, целочисленный счётчик или битовый.

Я только добавлю немного.

Есть темплейты. И в Квартусе и в ИСЕ и в Моделсиме. И их использование позволит не наступать на совершенно типовые грабли...

И даже более того. Я пользуюсь редактором EditPlus и у него можно создавать собственные темплейты из любимых кусков кода и потом вставлять их в нужное место просто одним кликом...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3. не использовать такую манеру написания кода, а явно прописывать для данного примера изменение сигнала cnt по условию else условного оператора. Но тогда много придется править для случаев, в которых сигнал сбрасывается в определенных условиях оператора case.

Подскажите, как правильно поступить?

В сложных случаях можно присваивать промежуточные значения временной переменной с диапазоном, на единицу большим, а в конце процесса перенести окончательное значение в сигнал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема как в типе, так и в логике работы.

 

    if (cnt= CNT_MAX- 1) then
        cnt<= 0;
    else
        cnt<= cnt+ 1;
   end if;

 

Если использовать тип unsigned, то переполнение не будет приводить к ошибке, и получится удобный счетчик по модуля 2^N

Поступаю, может сложнее, но в последствии гораздо удобнее. Через generic объявляю длины счетчиков и векторов (если их несколько). А затем использую такую конструкцию

use ieee.numeric.atd.all;
....
entity Name is
generic( dwidth:natural:=16;
max:natural:=65000);
port();
end entity;
..................
begin
........
process
variable cnt:unsigned(dwidth-1 downto 0):=to_unsigned(0,dwidth);--объявляем счетчик
constant zero:unsigned(dwidth-1 downto 0):=to_unsigned(0,dwidth);-- нуль
constant step:unsigned(dwidth-1 downto 0):=to_unsigned(1,dwidth);--шаг для счетчика
constant maxc:unsigned(dwidth-1 downto 0):=to_unsigned(max,dwidth);--предел счета
.....
if(cnt>=maxc)then
   cnt:=zero;
else
  cnt:=cnt+step;
end if;

По мне, такой код становится гибче за счет простой замены параметров в generic. И весьма удобно при структурном описании - задал параметр и вот новый счетчик с нужной разрядностью.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...