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

Схемотехнические трюки для ПЛИСоводов

Сравнение с нулём - это простое ИЛИ всех битов счётчика.

 

Сравнение с каким-то числом - это сначала XOR с заданным значением, после чего уже ИЛИ всех битов результата.

Но в ПЛИС то это реализуется на LUT (Look-Up Table) и на них без разницы как сравнивать, нули или конкретное значение.

Просто сказанное ниже, я имел ввиду применительно к ПЛИС:

А какая разница ? Компаратору без разницы, что сравнивать, схема у него одинаковая, что для сравнения нулей или других чисел.
Изменено пользователем Flip-fl0p

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


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

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

 

Другой вопрос, если нам надо например одним счетчиком отсчитывать разные интервалы. Например:

Счетчик досчитал до 10 - что-то делаем, и сбрасываем счетчик.

Счетчик досчитал до 15 - что-то делаем, и сбрасываем счетчик.

Счетчик досчитал до 18 - что-то делаем, и сбрасываем счетчик.

Счетчик досчитал до 24 - что-то делаем, и сбрасываем счетчик.

Счетчик досчитал до 32 - что-то делаем, и сбрасываем счетчик.

В этом случае у нас будет несколько схем сравнения с 10, 15, 18, 24, 32 - что собственно совсем не хорошо.

В случае если счетчик считает до 0 у нас будет только 1 схема сравнения с нулем.

 

А установка регистра счетчика в какую-то начальную величину не будет занимать логику? Т.е., получается, при счете до нуля мы тратим логику на инициализацию счетчика, а при счете до константы тратим логику на сравнение значения счетчика с константой, я правильно понимаю?

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


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

Если сравнивать с нулем и только с нулем, а при загрузке задавать произвольное значение счетчика, будет проще и быстрее, чем сравнивать с произвольным значением и сбрасывать счетчик.

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


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

Но в ПЛИС то это реализуется на LUT (Look-Up Table) и на них без разницы как сравнивать, нули или конкретное значение.

Просто сказанное ниже, я имел ввиду применительно к ПЛИС:

Даже если LUT, то в случае ИЛИ - одна ячейка обрабатывает столько бит входных данных, сколько у неё входов, в случае же сравнения с загруженным числом, на каждый бит нужен регистр. Да и интерконнект сильнее нагружается. Хотя, тут настаивать не буду - с ПЛИСами работаю крайне мало.

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


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

Если сравнивать с нулем и только с нулем, а при загрузке задавать произвольное значение счетчика, будет проще и быстрее, чем сравнивать с произвольным значением и сбрасывать счетчик.

 

Почему так? Как было сказано выше, компаратору нет разницы, какие данные у него на входе. Нули-не нули, он все равно будет их сравнивать, так же, как и полноценные данные.

 

Ну и с точки зрения наглядности - гораздо понятнее событие, которое происходит через Н тактов (запись cnt == N), чем событие, которое происходит, когда счетчик в 0( cnt == 0, а инициализация где-то в другой части модуля, например). Хотя тут уже вопрос привычки, я думаю.

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


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

Почему так? Как было сказано выше, компаратору нет разницы, какие данные у него на входе. Нули-не нули, он все равно будет их сравнивать, так же, как и полноценные данные.

Как было сказано выше :-), сравнить только с нулем - это объединить биты по ИЛИ.

Кроме того, я вообще не сравниваю биты счетчика, а использую бит переноса. Которым загружаю в счетчик число, хранящееся в рядом находящемся регистре.

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


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

Как было сказано выше :-), сравнить только с нулем - это объединить биты по ИЛИ.

Кроме того, я вообще не сравниваю биты счетчика, а использую бит переноса. Которым загружаю в счетчик число, хранящееся в рядом находящемся регистре.

А можете проилюстрировать в коде?

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


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

Вот. Последние варианты (4 и 5, одинаковые). Остальные показывают процесс разработки. :-)

 

`define LENTH	28
`define VAR5

`ifdef VAR1
`define TIM1
`elsif VAR2
`define TIM1
`elsif VAR3
`define TIM1
`else
`define TIM2
`endif

module Timer_m
`ifdef TIM1
(
 (* chip_pin = "91",
    altera_attribute = "-name global_signal on; -name io_standard lvds" *)
 input bit			clk,	// high-speed clock
 input bit	[`LENTH-1:0]	rld,	// reload data
 output bit			pls	// timer overload pulse
);
`endif

`ifdef VAR1
 bit [`LENTH:0]	cnt;
 always_ff @(posedge clk) begin
   if (cnt[`LENTH]) cnt <= {1'b0, rld};
   else             cnt <= cnt - 1;
 end
 assign pls = cnt[`LENTH];

`elsif VAR2
 bit [`LENTH-1:0]	cnt;
 always_ff @(posedge clk) begin
   if (cnt[`LENTH-1]) cnt <= rld;
   else               cnt <= cnt - 1;
 end
 assign pls = cnt[`LENTH-1];

`elsif VAR3
 bit [`LENTH-1:0]	cnt;
 always_ff @(posedge clk) begin
   if (cnt[`LENTH-1]) cnt <= rld;
   else	       cnt <= cnt[`LENTH-2:0] - 1;
 end
 assign pls = cnt[`LENTH-1];
`endif

`ifdef TIM2
(
 (* chip_pin = "91",
    altera_attribute = "-name global_signal on; -name io_standard lvds" *)
 input bit			clk,	// high-speed clock
 input bit	[`LENTH-1:0]	rld,	// reload data
 input bit			ldp,	// load pulse
 output bit			pls	// timer overload pulse
);
`endif

`ifdef VAR4
 bit [`LENTH:0]	cnt;
 always_ff @(posedge clk) begin
   if (cnt[`LENTH]) cnt <= {ldp, rld};
   else	     cnt <= cnt[`LENTH-1:0] - 1; 
 end
 assign pls = cnt[`LENTH];
`endif

`ifdef VAR5
 bit [`LENTH-1:0]	cnt;
 always_ff @(posedge clk) begin
   if (pls) {pls, cnt} <= {ldp, rld};
   else     {pls, cnt} <= cnt - 1;
 end
`endif

endmodule : Timer_m

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


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

Если речь о счётчике, то выгодней вообще не сравнивать все биты, а прекращать счёт при смене знака, то есть при переходе 0 -> -1 или -1 -> 0 в зависимости от направления счёта.

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


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

Может кому пригодится. Обычный счетчик с синхронным сбросом и сигналом разрешения работы.

Основной "фишкой" счетчика является возможность выбора направление счета, и уменьшение занимаемого места если коэффициент пересчета это 2^n.

 

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

ENTITY KAA_COUNTER_ENA_SCLR IS
   GENERIC
   (
       DIRECTION      : STRING  := "UP";                 -- UP / DOWN Направление счета 
       MAX_VALUE      : INTEGER := 127                   -- До скольки считает счетчик(от нуля до MAX_VALUE)
   );
   PORT
   (
       CLK            : IN  STD_LOGIC;
       ENA            : IN  STD_LOGIC; 
       SCLR           : IN  STD_LOGIC;
       DATA_OUT       : OUT INTEGER RANGE 0 TO MAX_VALUE
   );
END ENTITY;

ARCHITECTURE RTL OF KAA_COUNTER_ENA_SCLR IS
   --=====================================================================
   -- Функция определения разрядности шины - логарифм по основанию 2
   --=====================================================================
   FUNCTION LOG2 (MAX_VALUE : INTEGER) RETURN INTEGER IS             -- Функция вычесления логарифма по основанию 2 для определения разрядности
       VARIABLE CNT    : INTEGER := 0;                               -- Счетчик для подсчета количества делений на 2
       VARIABLE TEMP   : INTEGER := MAX_VALUE + 1;                   -- Делимое - это максимальное количество СОСТОЯНИЙ счетчика
   BEGIN
       WHILE (TEMP > 1) LOOP                                         -- Пока делимое больше 1 совершаем цикл деления на 2
           CNT  := CNT + 1 ;                                         -- Считаем количество циклов деления
           TEMP := TEMP/2;                                           -- Делим число на 2 каждый цикл
       END LOOP;
       RETURN CNT;                                                   -- Значение счетчика и есть логарифм
   END LOG2;

   SIGNAL COUNTER_INTEGER  : INTEGER RANGE 0 TO MAX_VALUE         := 0;           -- Счетчик обнуляемый условием максимального счета
   SIGNAL COUNTER_UNSIGNED : UNSIGNED(LOG2(MAX_VALUE)-1 DOWNTO 0) := (others => '0');   -- Счетчик с автомватическим обнулением при переполнении 
BEGIN

   --================================================================================
==========================
   -- Если максимальное значение счетчика переведенное в двоичное число не состоит из одних только единиц
   -- Значит у нас счетчик обнуляется значением максимального счета т.е до наступления переполнения разрядов
   --================================================================================
==========================
   COUNTER_INTEGER_GEN : IF ( TO_UNSIGNED(MAX_VALUE,LOG2(MAX_VALUE) ) /= ( LOG2(MAX_VALUE)-1 DOWNTO 0 => '1' ) ) GENERATE
       CNT_PROC : PROCESS
       (
           CLK
       )
       BEGIN
           IF (RISING_EDGE(CLK)) THEN         
               --==========================================================================
               -- Генерируем суммирующий счетчик обнуляющийся максимальным значением счета 
               --==========================================================================
               IF (DIRECTION = "UP") THEN                             -- Если направление счета "вверх" генерируется суммирующий счетчик
                   IF (ENA = '1') THEN                                -- При активном сигнале разрешения раблоты
                       IF (COUNTER_INTEGER = MAX_VALUE) THEN          -- При наступлении максимального значения счетчика
                           COUNTER_INTEGER <= 0;                      -- Обнулим его
                       ELSE
                           COUNTER_INTEGER <= COUNTER_INTEGER + 1;    -- Иначе будем его инкрементировать
                       END IF;
                   END IF;
                   IF (SCLR = '1') THEN                               -- При активном синхронном сбросе
                       COUNTER_INTEGER <= 0;                          -- Сбросим счетчик в ноль
                   END IF;
               END IF;
               --==========================================================================
               -- Генерируем вычитающий счетчик обнуляющийся максимальным значением счета 
               --==========================================================================
               IF (DIRECTION = "DOWN") THEN                           -- Если направление счета "вниз" то генерируется вычитающий счетчик
                   IF (ENA = '1') THEN                                -- При активном сигнале разрешения раблоты
                       IF (COUNTER_INTEGER = 0) THEN                  -- При наступлении максимального значения счетчика
                           COUNTER_INTEGER <= MAX_VALUE;              -- Обнулим его
                       ELSE
                           COUNTER_INTEGER <= COUNTER_INTEGER - 1;    -- Иначе будем его декрементировать
                       END IF;
                   END IF;
                   IF (SCLR = '1') THEN                               -- При активном синхронном сбросе
                       COUNTER_INTEGER <= MAX_VALUE;                  -- Сбросим счетчик в максимальное значение
                   END IF;
               END IF;
           END IF;
       END PROCESS;               
       DATA_OUT <= COUNTER_INTEGER;                                   -- Выдадим значение счетчика на выходные порты модуля
   END GENERATE; 

   --================================================================================
==========================
   -- Если максимальное значение счетчика это (2**N - 1)
   -- Значит у нас полный счетчик, который обнуляется переполнением разрядов
   --================================================================================
==========================
   COUNTER_UNSIGNED_GEN : IF ( TO_UNSIGNED(MAX_VALUE,LOG2(MAX_VALUE) ) = ( LOG2(MAX_VALUE)-1 DOWNTO 0 => '1' ) ) GENERATE
       CNT_PROC : PROCESS
       (
           CLK
       )
       BEGIN    
           IF (RISING_EDGE(CLK)) THEN      
               --==========================================================================
               -- Генерируем суммирующий счетчик обнуляющийся переполнением разрядов
               --==========================================================================
               IF (DIRECTION = "UP") THEN                                           -- Если направление счета "вверх" генерируется суммирующий счетчик
                   IF (ENA = '1') THEN                                              -- При активном сигнале разрешения раблоты
                       COUNTER_UNSIGNED <= COUNTER_UNSIGNED + "1";                  -- Инкрементируем его каждый такт
                   END IF;
                   IF (SCLR = '1') THEN                                             -- При активном синхронном сбросе
                       COUNTER_UNSIGNED <= (OTHERS => '0');                         -- Сбросим счетчик в ноль
                   END IF;
               END IF;
               --==========================================================================
               -- Генерируем вычитающий счетчик обнуляющийся переполнением разрядов
               --==========================================================================
               IF (DIRECTION = "DOWN") THEN                                          -- Если направление счета "вниз" то генерируется вычитающий счетчик
                   IF (ENA = '1') THEN                                               -- При активном сигнале разрешения раблоты
                       COUNTER_UNSIGNED <= COUNTER_UNSIGNED - "1";                   -- Декрементируем его каждый такт
                   END IF;
                   IF (SCLR = '1') THEN                                              -- При активном синхронном сбросе
                       COUNTER_UNSIGNED <= TO_UNSIGNED(MAX_VALUE,LOG2(MAX_VALUE) );  -- Сбросим счетчик в единицы
                   END IF;
               END IF;
           END IF;
       END PROCESS;   
       DATA_OUT <= TO_INTEGER(COUNTER_UNSIGNED);                                     -- Выдадим значение счетчика на выходные порты модуля
   END GENERATE;
END ARCHITECTURE;

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


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

Нет проверки на то, что что в DIRECTION будет нечто, отличное от "UP" и "DOWN". Например, "Up" или "Down". Не всем нравится верхний регистр. Лучше заменить строку на boolean.

От счётчика с integer никакого профита. То же самое можно сделать двоичным счётчиком. Тем более, что вы не сможете сделать integer-счётчик более 32 бит.

Есть старый программистский трюк: если число x является степенью 2, то

x and (x - 1) = 0

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


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

Нет проверки на то, что что в DIRECTION будет нечто, отличное от "UP" и "DOWN". Например, "Up" или "Down". Не всем нравится верхний регистр. Лучше заменить строку на boolean.

От счётчика с integer никакого профита. То же самое можно сделать двоичным счётчиком. Тем более, что вы не сможете сделать integer-счётчик более 32 бит.

Есть старый программистский трюк: если число x является степенью 2, то

x and (x - 1) = 0

Спасибо за критику ! Я обязательно подумаю над этим.

Вот со счётчиками типа integer я не совсем согласен. Какой тип использовать в качестве выхода: SLV, integer, unsigned - зависит лишь от предпочтений разработчика. Никаких преимуществ SLV над integer нет, как и наоборот. Это лишь вопрос удобства. В конце концов, всегда значение можно преобразовать в тот тип, который нужен :smile3046:

Изменено пользователем Flip-fl0p

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


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

Никаких преимуществ SLV над integer нет, как и наоборот. Это лишь вопрос удобства. В конце концов, всегда значение можно преобразовать в тот тип, который нужен
Ну попробуйте сделать на integer счётчик разрядностью более 32 бит.

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


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

Ну попробуйте сделать на integer счётчик разрядностью более 32 бит.

Вы снова правы ! :biggrin:

Вот только мне ещё ни разу не приходилось работать с такими счетчиками...

Можете сказать навскидку где вообще такой счетчик мог бы пригодится ?

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


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

Можете сказать навскидку где вообще такой счетчик мог бы пригодится ?

Для адресации внешней SDRAM памяти объемом 128 ГБайт. :biggrin:

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


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

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

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

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

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

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

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

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

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

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