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

Verilog: как комбинаторикой узнать номер бита, установленного в 1?

Всем привет!

 

Тема такая: создаю схему на верилоге. В ней есть регистр переменного размера. Размер его задаётся через parameter, а затем выполняется перекомпиляция схемы. В результате работы схемы в регистре только один бит устанавливается в 1, остальные остаются в нуле. Вопрос: как комбинаторикой узнать номер этого установленного бита?

 

Вот, например, как это было бы мной реализовано, если бы регистр был постоянного размера, скажем, восьмибитовым:

reg [7:0] result_reg;

assign result_o = result_reg[7] ? 7 :
                  result_reg[6] ? 6 :
                  result_reg[5] ? 5 :
                  result_reg[4] ? 4 :
                  result_reg[3] ? 3 :
                  result_reg[2] ? 2 :
                  result_reg[1] ? 1 :
                  0;

А как это сделать если регистр переменного размера?

Пытаюсь сделать нечто в этом роде:

parameter XX = 8;        // Количество бит в регистре результата
parameter NB = log2(XX); // Логарифм по основанию 2 от XX (вычисляется функцией log2)

reg [XX-1:0] result_reg;  // Регистр с результатом работы схемы
reg [NB-1:0] num_bit_reg; // Номер установленного бита в регистре result_reg

assign result_o = num_bit_reg; // result_o - output-порт модуля

always @( result_reg )
begin

  integer i;

  for( i=0; i < XX; i=i+1 )
    if( result_reg[i] )
      num_bit_reg = i;

end

Компилируется и вроде даже работает как надо, но при компиляции выдаётся warning: inferring latch(es) for variable "num_bit_reg", which holds its previous value in one or more paths through the always construct.

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

 

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


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

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

Если на выходе нужен HEX - ставьте шифратор, если DEC - то достаточно сам регистр вывести. Если нужен признак установления единицы, надо все разряды через ИЛИ сжать до одного провода. Ну и т.д. Нарисуйте сначала схему, что получить хотите, а потом верилог пишите

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


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

На порту result_o нужно получить порядковый номер бита регистра result_reg, установленного в единицу. Например, если регистр result_reg имеет размер 8192 бита, и в нём установлен бит номер 4015, то на порту result_o нужно получить число 4015.

 

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


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

А цикл for тут не поможет? Пусть само синтезируется в комбинаторику...

 

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


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

Компилируется и вроде даже работает как надо, но при компиляции выдаётся warning: inferring latch(es) for variable "num_bit_reg", which holds its previous value in one or more paths through the always construct.

Как сделать так, чтобы этого варнинга не было?

Так там действительно защелка образуется. Чтобы ее не было, нужно перед "for" присвоить num_bit_reg значение по умолчанию, например 0.

 

Кстати, ваш код будет считать номер бита с конца. Чтобы считал сначала, нужно после "num_bit_reg = i" поставить "break".

 

Изменено пользователем embddr

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


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

Так там действительно защелка образуется. Чтобы ее не было, нужно перед "for" присвоить num_bit_reg значение по умолчанию, например 0.

 

Кстати, ваш код будет считать номер бита с конца. Чтобы считал сначала, нужно после "num_bit_reg = i" поставить "break".

Да, регистр был не инициализирован. Инициализировал. Всё равно варнинг рисуется. Посмотрел сгенерённую схему: куча комбинаторики и в самом конце стоят защёлки - в них используются входы ACLR и PRESET.

 

А насчёт порядка счёта: без разницы откуда считать. Единичный бит в регистре только в одном экземпляре.

 

PS: Добавил в цикл break - перестало компилироваться. Выдаёт ошибку: can't resolve reference to object "break".

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


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

Да, регистр был не инициализирован. Инициализировал. Всё равно варнинг рисуется. Посмотрел сгенерённую схему: куча комбинаторики и в самом конце стоят защёлки - в них используются входы ACLR и PRESET.

 

А насчёт порядка счёта: без разницы откуда считать. Единичный бит в регистре только в одном экземпляре.

 

PS: Добавил в цикл break - перестало компилироваться. Выдаёт ошибку: can't resolve reference to object "break".

 

Вот такой код должен быть:

always @( result_reg )
begin
  integer i;
  num_bit_reg = 0;

  for( i=0; i < XX; i=i+1 )
    if( result_reg[i] )
      num_bit_reg = i;
end

 

Это квартус? Ошибка на 'break' потому, что его нет в Verilog-е. Нужно поставить тип файла SystemVerilog. В Verilog-е можно использовать 'disable'.

Изменено пользователем embddr

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


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

2 embddr:

 

Да, точно! Я понял в чём была моя ошибка. Теперь всё синтезируется без варнинга и защёлок. Большое спасибо за помощь!

 

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


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

for( i=0; i < XX; i=i+1 )

if( result_reg )

num_bit_reg = i;

 

 

Компилируется и вроде даже работает как надо, но при компиляции выдаётся warning: inferring latch(es) for variable "num_bit_reg", which holds its previous value in one or more paths through the always construct.

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

Латчи получаются если не доопределены все состояния шифратора. Введите условие else и там напишите что нужно.

Подробнее читайте в "Кратком Курсе"...

Удачи!

 

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


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

Введите условие else и там напишите что нужно.

 

В данном конкретном случае с else не получится.

 

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


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

На порту result_o нужно получить порядковый номер бита регистра result_reg, установленного в единицу. Например, если регистр result_reg имеет размер 8192 бита, и в нём установлен бит номер 4015, то на порту result_o нужно получить число 4015.

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

Один из вариантов такой.

Регистр разбивается на блоки, каждый из которых обрабатывает соседние разряды регистра. При этом число разрядов входящих в блок задается из ряда 2, 4, 8 или 16, а из блока выходят сигнал наличия единицы в блоке (СНЕ) и код ее позиции (КП), если единица там есть.

Далее блоки группируются в слои, первый слой блоков подключен к регистру, а каждый последующий слои принимает сигналы наличия единицы (СНЕ) из блоков предыдущего слоя. И так до тех пор, пока слои не закончатся, получается что-то похожее на двоичную пирамиду.

Теперь в каждом слое блоков должен быть один большой коммутатор, входы которого подключены к выходам кодов КП блоков, а управляться коммутатор должен сигналами СНЕ этого слоя.

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

Похоже, что задача относится к цифровой части АЦП...

 

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


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

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

кстати у ТС нет клока, потому про конвейер трудно говорить...

 

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


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

по-моему тоже обычный шифратор.

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

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


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

по-моему тоже обычный шифратор.

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

Еще один вариант с методом двоичного взвешивания.

Весь N- разрядный регистр делится на две части, и разряды старшей части подключаются к элементу ИЛИ на N/2 входов. Сигнал на выходе элемента ИЛИ укажет, в старшей или младшей части регистра находится значащая единица, и по сути он есть самый старший разряд результата. Далее разряды обеих частей регистра подаются на двухвходовой N/2-разрядный коммутатор, который пропускает для дальнейшего анализа часть кода со значащей единицей (здесь старшая часть выбирается единицей, а младшая нулем).

На второй итерации имеем уже N/2-разрядный код, который также делится пополам и старшие N/4 разрядов также подключаются к элементу ИЛИ, но уже на N/4 входов. На выходе элемента ИЛИ формируется уже второй слева разряд результата, а обе части кода подаются на двухвходовой N/4-разрядный коммутатор, который пропускает для дальнейшего анализа часть кода также со значащей единицей.

Далее выполняются аналогичные итерационные действия, в которых разрядность элемента ИЛИ и соответствующего ему коммутатора в два раза меньше чем в предыдущей итерации. То есть реализуется метод двоичного взвешивания..

Быстродействие здесь достаточно большое...

Так что это за задача, где еще приходится находить позицию единицы?

В приложении схема этого варианта

1.rar

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


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

На порту result_o нужно получить порядковый номер бита регистра result_reg, установленного в единицу. Например, если регистр result_reg имеет размер 8192 бита, и в нём установлен бит номер 4015, то на порту result_o нужно получить число 4015.

 

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

 

 

мне как то надо было проверить массив переменной длинны с шинами фиксированной размерности на наличие хотя бы одной 1. на вхдл-е я это так сделал.

 

process(bu_data_v)
begin
for i in 31 downto 0 loop
		for j in 1 to num_adc loop
			if bu_data_v(j)(i)='1' then bu_data(i)<='1';
			end if;
			bu_data(i)<='0';
		end loop;	
end loop;
end process;

 

насколько это разводибельно - пока не проверял :blush: , но человек, интегрирующий мой блок в общий проект пока что на него не жаловался :)

 

вам достаточно запоминать номер индекса, на котором получена "1"

 

зы

упс, не дочитал... embddr уже предложил это решение :)

Изменено пользователем GAYVER

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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