[an error occurred while processing this directive]
|
Привет ! Извиняюсь, жопа я обыкновенная, а не Его Помоечное Мурлычество. Это надо же, сунуть сюда модуль из своего проекта, с кучей совершенно не относящейся к делу мишуры... Короче самому уже стыдно. Работает это по хорошо известному алгоритму генерации псевдослучайной последовательности максимальной длинны на сдвиговом регистре с обратными связями. Константа mask=0x82608edb это полином,
используемый в стандарте Ethernet для вычисления 32-битной CRC. Если код объяснять совершенно на пальцах, происходит тут следующее. Есть 32-битный сдвиговый регистр. Его старший бит (31) запоминается в триггере-защелке P(latch), управляемом уровнем тактового сигнала. Запоминание происходит когда тактовый сигнал равен 0. Бит P в свою
очередь управляет мультиплексером, на выходе которого появляется константа mask, если P=1, и все нули если P=0. По положительному фронту тактового импульса в регистр записывается значение, полученное сдвигом регистра на 1 бит влево, к которому затем применяется XOR с выходом мультиплексора. Вот собственно и всё. Теперь код, очищеный от шелухи.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
entity rand is
port(
rst : in std_logic; -- сброс
clk : in std_logic; -- тактовый сигнал
do : out std_logic_vector(31 downto 0) -- случайное число
);
architecture rand of rand is
constant mask : std_logic_vector(31 downto 0):=X"82608edb"; -- полином
signal reg : std_logic_vector(31 downto 0); -- сдвиговый регистр
signal р : std_logic; -- триггер-защелка
signal smsk : std_logic_vector(31 downto 0); -- выход мултиплексора
signal shft : std_logic_vector(31 downto 0); -- сдвинутый регистр
signal back : std_logic_vector(31 downto 0); -- обратная связь
begin
smsk<=mask when p='1' else (others=>'0'); -- мультиплексор
shft(31 downto 1)<=reg(30 downto 0); shft(0)<='0'; -- сдвиг регистра
back<=smsk xor shft; -- полный сигнал обратной связи
--Тут синтезируется тригер-защелка и синтезатор может выдавать
--предупреждения, которые надо херить, ибо так оно и задумано.
process(rst, clk, reg(31)) -- управление битом p
begin
if rst='1' then p<='1'; -- 1 при сбросе (в принципе можно похерить)
else
if clk='0' then p<=reg(31); -- при клоке = 0 пишем туда reg(31)
end if;
end if;
end process;
process(rst, clk) -- управление сдвиговым регистром.
begin
--При сбросе пишем 0xffffffff или любое другое значение, не равное 0
if rst='1' then reg<=X"ffffffff";
else
-- по фронту клока пишем в регистр сигнал обратной связи.
if clk'event and clk='1' then reg<=back;
end if;
end if;
end process;
do<=reg; -- подаем значение регистра на выход
end rand;
Как видим, всё очень просто и даже вполне синтезабельно.
Юзается модуль элементарно. На rst подается сигнал сброса (активный
уровень 1), на clk - тактовая частота (активный фронт положительный).
Сбросом переводим в начальное состояние. Затем получаем новое случайное число после каждого клока. Читаем его с шины do.
Наконец, функция на С, делающая абсолютно то же самое. Желающие могут
убедиться, что и С и VHDL порождают совершенно одинаковую последовательность случайных чисел (естественно при одинаковом начальном значении).
static unsigned int seed=0xffffffff;
static unsigned int mask=0x82608edb;
unsigned int GetRand(void)
{
if(seed & 0x80000000) {seed <<=1; seed ^= mask;}
else seed <<=1;
return seed;
}
void SetSeed(int s) {seed=s;}
Надеюсь теперь любой сможет это написать хоть на верилоге, хоть на вижуалбейсике :)
С почтением
Его Мурлычество Мартовский Кот.
Гроза мышей, бомжей и тараканов :)
E-mail: info@telesys.ru