Generate random number in range using LFSR

neanton28

Junior Member level 1
Joined
Jul 21, 2024
Messages
16
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
192
Greetings! I am trying to find best way for random generator in specific range and was wondering what are the best practices for now.
I have array of 360 numbers each of one is +4 of previous:
Code:
constant possible_values : t_int_array :=(4,8,12, n+4...1432,1436);

And I'd like to have some function that accepts seed/code and output numbers from this array in random way. Numbers may also be not initially stored in array, but also generated in some function during execution. This will save some on-chip RAM.

For now I am still looking for proper way of such limitation pure LFSR, since it will just generate me random numbers, and not what I need. Maybe there is some graceful way to do it, to not add conditions like (if result > 1436 then generate again)

That's some example vhdl block I created for demonstration:
Code:
library IEEE;
use IEEE.std_logic_1164.all;

entity offset_generator is
     port(
         clk : in STD_LOGIC;
         reset : in STD_LOGIC;
         seed : in STD_LOGIC_VECTOR(32 downto 0);
         result : out STD_LOGIC_VECTOR(10 downto 0)
         );
end offset_generator;



architecture offset_generator of offset_generator is
signal s_result : STD_LOGIC_VECTOR(10 downto 0) := (others => '0');

    type t_int_array is array(natural range 0 to 360) of natural range 0 to 1436;
    constant possible_values : t_int_array :=(4,8,12,16,....,1432,1436);
    
    signal s_seed : STD_LOGIC_VECTOR(32 downto 0) := (others => '0');
    
          
    function GET_RANDOM (seed : in STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is
    begin
        return INSERT_IMPLEMENTATION_HERE;
    end;
    
begin
    result <= s_result;
    
    process( clk )
    begin
        if (rising_edge(clk)) then
            if (reset = '1') then
                s_seed <= seed;
            else
                s_result <= GET_RANDOM(s_seed);
            end if;
        end if;
    end process;   
end offset_generator;
 

Hi,

I understand this all is done on the Tx side.
But I have no clue how it can be done on the Rx side.
Scrambled BT.656 .. especially when processed A->D->A .. you lost the markers ... in my opinion.
Even the markers are scrambled.

But again: I don´t need to understand you whole process ....

Klaus
 

504 * 719 = 362376
Divide by 1024 (discard 10 LSBs)= 353 (or 354 if rounded)
Now output adding two zero LSBs
353 * 4= 1412

Code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity offset_generator is
     port(
         clk : in STD_LOGIC;
         reset : in STD_LOGIC;
         seed : in STD_LOGIC_VECTOR(8 downto 0);
         result : out STD_LOGIC_VECTOR(10 downto 0)
         );
end offset_generator;

architecture offset_generator of offset_generator is
    signal s_result : STD_LOGIC_VECTOR(10 downto 0) := (others => '0');
    signal s_lfsr : STD_LOGIC_VECTOR(8 downto 0) := (others => '1');  
    signal linear_feedback :std_logic;
    --signal s_temp : unsigned(18 downto 0);
   
    signal s_stub_lfsr : STD_LOGIC_VECTOR(8 downto 0) := b"1_1111_1000"; --504
   
    signal s_temp_lfsr : unsigned(8 downto 0);
    signal s_x719_lfsr : unsigned(18 downto 0);
    signal s_divided_lfsr : unsigned(8 downto 0);
    signal s_x4_lfsr : unsigned(10 downto 0);
begin
    result <= s_result;
    linear_feedback <= s_lfsr(8) xor s_lfsr(3);
    --s_temp <= to_unsigned( ((to_integer( unsigned(s_lfsr) ) * 719) / 1024) * 4, 19);

    s_temp_lfsr <= unsigned(s_stub_lfsr);
   
    s_x719_lfsr <= s_temp_lfsr * 719; --"101_1000_0111_1000_1000"  504*719=362376
   
    s_divided_lfsr <= s_x719_lfsr(18 downto 10); --"1_0110_0001" division 362376/1024=353
   
    s_x4_lfsr <= s_divided_lfsr & b"00"; -- 353*4=1412 multiply by 4
   
    process( clk )
    begin
        if (rising_edge(clk)) then
            if (reset = '1') then
                s_lfsr <= seed;
            else
                s_lfsr(8 downto 0) <= s_lfsr(7 downto 0) & linear_feedback;
            end if;
        end if;
    end process;  
end offset_generator;

When I define multiplications in one line, in simulation it works:
Code:
s_temp <= to_unsigned( ((to_integer( unsigned(s_lfsr) ) * 719) / 1024) * 4, 19);

But when I split it in several operations for clarity, I get error on compilation and simulation at line:
Code:
s_x719_lfsr <= s_temp_lfsr * 719; --"101_1000_0111_1000_1000"  504*719=362376

Message: Warning: COMP96_0367: offset_generator.vhd : (33, 17): Improper array length (18). Expected length is 19.

This look weird because all dimensions match
--- Updated ---

Ah, no worries. I scramble not whole line, but only active video part. This way all markers stay in their position.
Format of BT.656 is like this: EAV|80|10|80|10...|SAV|01|02|03|04|...

EAV - is start marker of line
80|10| - is sequence of blanking bytes
SAV - is start of active video bytes
01|02|03|04 - is sequence of 1440 bytes of actual video data. I scramble only this part, making it like |200|201|202|....|1436|1440|01|02|03|04|...|197|198|199|
--- Updated ---

Hm, I changed decimal 719 to binary format b"10_1100_1111" and error went away.
Here is result of simulation. All numbers in decimal format:

Works well, thanks! Now will try to add such code to fpga project and to synthesize. Curious how many LUTs it will take on fpga without hardware multiplier.

So for current 9-bit LFSR it requires 9x10 bit multiplier. Since 719 takes 10 bits
--- Updated ---

I am curious if there are some universal rules or tips of how to create such number generators for different scales/values. I bet I am not the first who tries to implement this pseudo-random generator among fixed set of values
 
Last edited:

Cookies are required to use this site. You must accept them to continue using the site. Learn more…