Usage of random functions (e.g RandSlv)
Why OSVVM™? › Forums › OSVVM › Usage of random functions (e.g RandSlv)
Tagged: Randomisation Randslv
- This topic has 3 replies, 2 voices, and was last updated 9 years ago by Jim Lewis.
-
AuthorPosts
-
November 18, 2015 at 02:13 #1071Eilert BackhusMember
Hi,
I’m trying to use the randomisation package in a simple testbench, to evaluate the usage concepts of OSVVM.
My idea was to write a function or procedure that contains a Random Data Generator and a Bus Function Model for the UUT.
Since my UUT is now a simple register the BFM part is a simple assignment to the return value.
Now my function and procedure properly sets a seed, and maybe even a second random value, but then the random generator stucks at theat value.
I then wrote a process that basically has the same function, but needs to be triggered (see code below).
My guess is, that the variables in the functions and procedures are not static, and so the (pseudo) random generator starts all over from the seed.
Is there some method to overcome these problems?
impure function DataGenerator(Data : std_logic_vector) return std_logic_vector is
variable RandomData : RandomPType;
variable Dummy : std_logic_vector(Data'range);
begin
if Data(Data'low) = 'U' then
RandomData.InitSeed(RandomData'instance_name);
report "Seed generated for RandomData";
end if;
return RandomData.RandSlv(0,2**Data'high-1, Data'length);
end function;-----
procedure DataGenerator (Signal Data: inout std_logic_vector) is
variable RandomData : RandomPType;
begin
if Data(Data'low) = 'U' then
RandomData.InitSeed(RandomData'instance_name);
report "Seed generated for RandomData";
end if;
Data <= RandomData.RandSlv(2**DataIn'high-1, DataIn'length);
end procedure;—-
DataGenerator : process (DatagenTrigger) is
variable RandomData : RandomPType;
begin
if Data(Data'low) = 'U' then
RandomData.InitSeed(RandomData'instance_name);
report "Seed generated for RandomData";
end if;
Data <= RandomData.RandSlv(2**DataIn'high-1, DataIn'length);
end process;-- The calling lines:
DataIn <= DataGenerator(DataIn); --for Function Call
DataGenerator(DataIn); -- for procedure call
DatagenTrigger <= not DatagenTrigger; -- event assignment (boolean)
DataIn <= Data; -- assign updated random value(Sorry, but highlighting could not be removed)
Each method was compiled and ran successfully on Questa Sim 10.4.
But as mentioned above the random values stuck in procedure and function.
I then assigned a new seed on every call:
if Data(Data'low) = 'U' then
RandomData.InitSeed(RandomData'instance_name);
report "Seed generated for RandomData";
else
RandomData.InitSeed(to_integer(unsigned(Data)));
end if;But this just caused the random data to toggle between two values.
Any suggestions how to deal with this?
Kind regards
Eilert
November 18, 2015 at 09:20 #1072Jim LewisMemberHi Eilert,
If you create a randomization object (your RandomData variable) in a procedure or function, it will only be “live” when the procedure is called. Hence, in your procedure/function, there are only two different values of the seed, the default value (set by the package) and the value generated when InitSeed is called.
My recommendation is to pass the randomization object to the procedure:
procedure DoMyRandomization(
variable RV : InOut RandomPType ;
. . .
);Then in the process, you would need to declare an object of RandomPType.
There are examples in the RandomPkg User Guide that you can put loops around and try out.
Jim
November 19, 2015 at 01:16 #1073Eilert BackhusMemberHi Jim,
thanks for that recommendation.
Meanwhile I found another working solution too.
For using the RandomPType QuestaSim insists that the function has to be impure. I remembered from your documentations that there’s some link between protected types, shared variables and impure functions.
So I came up with this solution:
shared variable RandomData : RandomPType;
impure function DataGenerator(DataWidth : natural) return std_logic_vector is
begin
-- check seed for initial value (from RandomBasePkg Random Seed declaration)
if RandomData.GetSeed = RandomSeedType(integer_vector'(1,7)) then
RandomData.InitSeed(RandomData'instance_name);
report "Info: Seed generated for DataGenerator:RandomData";
end if;
return RandomData.RandSlv(0, 2**Datawidth-1, DataWidth);
end function;And calling the Function like this works just fine:
for i in 0 to 99 loop
wait until falling_edge(clock); -- just creating some delay
DataIn <= DataGenerator(DataIn'length);
wait until rising_edge(clock);
end loop;I think it would work with a procedure as well. (hopefully)
The good thing is that I do not have to double declare the RandomPType outside and inside the function and do not have to transfer the actual values. Instead I just have a constant in the function argument list.
Thanks for reminding me about the Random Package UG.
I saw it was there, but just read the OSVVM UG and the Protected types paper. Somehow I couldn’t resist to try it out immediately. 🙂
Kind regards
Eilert
December 4, 2015 at 07:38 #1082Jim LewisMemberHi Eilert,
The only issue with functions and procedures of this sort is if they are called from more than one process. When two processes share a common seed and randomize at the same time, the test will be unstable – meaning if you recompile the test, the processes may call the function/procedure in a different order (due to both requesting it during the same delta cycle and optimization changing which one gets scheduled first), and as a result the test will produce different results than it did previously.
Hence, this is why I suggest passing the randomization object into the procedure instead. Unfortunately when you pass in the protected type, a function is no longer possible.
Cheers,
Jim
-
AuthorPosts
- You must be logged in to reply to this topic.