События счет любят
Sep. 24th, 2010 12:22 amДаже не знаю, кому будет интересно. Математикам банально, программистам неактуально, электронщикам и так известно, остальным пофиг. Поэтому ...
Допустим, что нам для некоторого эксперимента нужно считать, сколько раз случилось каждое из многих десятков или сотен тысяч событий. Для этого мы разрабатываем специализированные чипы, каким-то умным образом анализирующие сырые данные эксперимента и получающие внутри себя много сигналов "случилось такое-то событие".
События могут происходить в произвольных сочетаниях - хоть все сотни тысяч одновременно, и - по сравнению с тактовыми частотами современных процессоров, - весьма часто. Это значит, что к схеме тех специализированных чипов придется добавить много блоков, которые только и умели бы, что по сигналу "произошло событие" как можно быстрее прибавлять 1 к счетчику (ну и по управляющему сигналу позволяли бы сбрасывать счетчик в ноль, одновременно выталкивая его текущее содержимое в порт - надо же нам как-то узнавать, до чего они там досчитали, но эту деталь функциональности мы пока для простоты опустим).
Как будет выглядеть такой блок? Он будет состоять из двух частей: регистра, где хранится текущее значение счетчика, и сложителя, прибавляющего 1 к счетчику. У регистра есть два входа - сигнал и новое значение. В момент прихода сигнала содержимое регистра заменяется новым значением. В сложитель же входит текущее значение регистра, а выходят из него провода, несущие "новое значение":
Таким образом, если события будут приходить с интервалом не меньшим, чем время, необходимое сложителю для прибавления единицы к, например, 64-битному числу, то наш регистратор будет работать.
Посмотрим теперь, как сложитель устроен внутри. Понятно, что из четного числа получается нечетное, и наоборот: new_value[0] = !counter[0];
Каждый следующий бит изменяется на противоположный, если все биты правее него были равны единице, или, что то же самое, если логическое И от всех этих битов равно единице:
Это довольно быстро становится или дорого с точки зрения количества необходимых логических элементов - если мы будем вычислять все частичные логические И параллельно, их потребуются сотни, или недопустимо медленно - если мы будем экономить и вычислять их по цепочке:
Да и то понадобится по два элемента (XOR и AND) почти на каждый бит счетчика.
Как же быть? Как сделать счетчик событий так, чтобы он, кроме собственно регистра, использовал самый минимум логических элементов?
Допустим, что нам для некоторого эксперимента нужно считать, сколько раз случилось каждое из многих десятков или сотен тысяч событий. Для этого мы разрабатываем специализированные чипы, каким-то умным образом анализирующие сырые данные эксперимента и получающие внутри себя много сигналов "случилось такое-то событие".
События могут происходить в произвольных сочетаниях - хоть все сотни тысяч одновременно, и - по сравнению с тактовыми частотами современных процессоров, - весьма часто. Это значит, что к схеме тех специализированных чипов придется добавить много блоков, которые только и умели бы, что по сигналу "произошло событие" как можно быстрее прибавлять 1 к счетчику (ну и по управляющему сигналу позволяли бы сбрасывать счетчик в ноль, одновременно выталкивая его текущее содержимое в порт - надо же нам как-то узнавать, до чего они там досчитали, но эту деталь функциональности мы пока для простоты опустим).
Как будет выглядеть такой блок? Он будет состоять из двух частей: регистра, где хранится текущее значение счетчика, и сложителя, прибавляющего 1 к счетчику. У регистра есть два входа - сигнал и новое значение. В момент прихода сигнала содержимое регистра заменяется новым значением. В сложитель же входит текущее значение регистра, а выходят из него провода, несущие "новое значение":
reg [63:0] counter;
wire [63:0] new_value = counter + 1; // Сложение происходит "непрерывно"
always @(signal) begin // Каждый раз, когда приходит сигнал (верилоговцы меня простят)
counter = new_value;
endТаким образом, если события будут приходить с интервалом не меньшим, чем время, необходимое сложителю для прибавления единицы к, например, 64-битному числу, то наш регистратор будет работать.
Посмотрим теперь, как сложитель устроен внутри. Понятно, что из четного числа получается нечетное, и наоборот: new_value[0] = !counter[0];
Каждый следующий бит изменяется на противоположный, если все биты правее него были равны единице, или, что то же самое, если логическое И от всех этих битов равно единице:
for (int i = 1; i < 64; i++) // Декларативный цикл, описывающий подключение отдельных битов new_value
new_value[i] = counter[i] ^ (counter[i-1:0] == (1 << i) - 1);Это довольно быстро становится или дорого с точки зрения количества необходимых логических элементов - если мы будем вычислять все частичные логические И параллельно, их потребуются сотни, или недопустимо медленно - если мы будем экономить и вычислять их по цепочке:
wire [63:0] ands;
assign ands[0] = counter[0];
for (int i = 1; i < 64; i++) begin
new_value[i] = counter[i] ^ ands[i-1];
if (i != 63) ands[i] = ands[i-1] & counter[i];
endДа и то понадобится по два элемента (XOR и AND) почти на каждый бит счетчика.
Как же быть? Как сделать счетчик событий так, чтобы он, кроме собственно регистра, использовал самый минимум логических элементов?
no subject
Date: 2010-09-24 07:38 am (UTC)Самое простое решение - делать несколько инкриметров параллельно. То есть пока расчитывается перенос от одного инкримента из n-ного разряда, можно уже начинать высчитывать перенос их n-1-го разряда для следующего. Правда схема чтения сильно усложниться.
Можно пропускать события через ряд делителей. Схема чтения упрощается, но фактически становятся недоступны несколько младшие несколько бит.
no subject
Date: 2010-09-24 07:47 am (UTC)Или считай через LFSR -- вообще один XOR на все про все. Только потом ответ нетривиально будет расшифровать...
no subject
Date: 2010-09-24 07:47 am (UTC)Отдельные инкременторы всегда работают параллельно и независимо.
Делители недопустимы, каждое событие на счету.
Подсказка: искомое решение математически нетривиально.
no subject
Date: 2010-09-24 07:49 am (UTC)LFSR - правильный ответ.
no subject
Date: 2010-09-24 07:58 am (UTC)Вот сам входной сигнал и будем использовать как тактовый генератор.
no subject
Date: 2010-09-24 08:00 am (UTC)Параллельно может работать и отдельный инкрементатор, если второе событие пришло когда первое еще не до конца обработано - младший бит инвертировался, но перенос еще до старшего не дошел.
no subject
Date: 2010-09-24 08:02 am (UTC)no subject
Date: 2010-09-24 11:13 am (UTC)no subject
Date: 2010-09-24 03:41 pm (UTC)no subject
Date: 2010-09-24 03:48 pm (UTC)no subject
Date: 2010-09-24 03:51 pm (UTC)no subject
Date: 2010-09-24 03:56 pm (UTC)no subject
Date: 2010-09-24 06:05 pm (UTC)no subject
Date: 2010-09-24 06:20 pm (UTC)no subject
Date: 2010-09-24 06:30 pm (UTC)А воообще, спасибо, прочитал про LFSR, очень интересно. Кстати, есть какой-то простой метод декодирования из LFSR в порядковый номер?
no subject
Date: 2010-09-24 06:48 pm (UTC)Простейшим методом декодирования из N-битного LFSR в порядковый номер я считаю rainbow table: выбираем, сколько в среднем итераций мы готовы жертвовать на декодирование - пусть это 2M. Выбираем некоторый паттерн с фиксированными M битами - он будет в среднем встречаться через 2M итераций. Генерируем таблицу, сопоставляющую каждое (в случае большого N - каждое возможное на практике) значение, соответствующее паттерну, с порядковым номером. Тогда для декодирования нам потребуется лишь прогнать полученный результат вперед до ближайшего совпадения с паттерном, считая итерации, потом заглянуть в таблицу и вычесть.
no subject
Date: 2010-09-24 06:55 pm (UTC)То есть, даже учитывая линейность преобразования, не брут форсом всё равно не имеет смысла декодировать?
no subject
Date: 2010-09-24 07:17 pm (UTC)Декодирование LFSR эквивалентно нахождению дискретного логарифма, а это пока быстро делать не умеют.
no subject
Date: 2010-09-25 08:33 am (UTC)no subject
Date: 2010-09-25 08:39 am (UTC)no subject
Date: 2010-09-25 09:31 am (UTC)Для 63-й, 31-й и 15-й степеней есть полиномы с одним XOR-ом. Вполне практично.
no subject
Date: 2010-09-26 05:09 am (UTC)Очевидно, чтоб досчитать до N нужно минимум O(log(N)) элементов. Ну хотя б чтобы ответ выводить.
Вполне достаточно каскада флип-флопов. При поступлении сигнала на вход состояние счетчика переключается между 0 и 1, а каждый второй раз посылается сигнал на следующую стадию.
Если мои смутные воспоминания об электронике верны, то на все про все требуется 2 транзистора. Куда уж меньше-то.
no subject
Date: 2010-09-26 05:35 am (UTC)no subject
Date: 2010-09-26 05:42 am (UTC)?????
У него состояние заведено выход - бери и пользуйся.
Клоки помойму вообще не нужны - бывают асинхронные флип-флопы.
no subject
Date: 2010-09-26 06:14 am (UTC)Асинхронным флип-флопом обычно называется флип-флоп с асинхронными сбросом в 0 и установкой в 1.
no subject
Date: 2010-09-27 07:58 am (UTC)no subject
Date: 2010-09-27 08:00 am (UTC)Можно счетчик команд в процессоре таким же образом инкрементировать. :-)