I have a design were I'm writing/reading to/from a RAM and perform some computation on the read values. In some cases, I read values from RAM locations where I haven't written anything to yet. This is intentional because in the cases where this happens, the uninitialized values don't affect the computation: in these cases, the uninitialized values are multiplied with 0.
However, multiplying an unsigned
/signed
type which contains 'U'
bits results in a "don't care" output (i.e. all bits of the multiplication output are 'X'
) even if the other operand is 0. Therefore, I can't check the final computation output in my testbench because it becomes "don't care" (it seems like "don't care" outputs are interpreted as 0).
To avoid this problem, I wrote a function that resolves any 'U'
or 'X'
bits in a std_logic_vector
to '0'
. The functions looks as follows
function f(x : std_logic_vector) return std_logic_vector is
variable y : std_logic_vector (x'range);
begin
y := x;
-- pragma synthesis off
for i in 0 to x'length-1 loop
case x(i) is
when 'U' | 'X' => y(i) := '0';
when others => y(i) := x(i);
end case;
end loop; -- i
-- pragma synthesis on
return y;
end;
Now I'd like to expand the function by not only setting 'X'
and 'U'
bits to '0'
but to randomly set them to either '0'
or '1'
. I've tried using the uniform
function within f
. The problem is that when I define the two seeds within the function, that each time the function f
is called it returns the same std_logic_vector
(when it is given the same std_logic_vector
). As I take it from the uniform
function description, I should pass the two seeds from outside the function f
because they are modified by the uniform
function for the next call to uniform
.
Is there a possibility how this can be achieved using a function?
There's a very good random library as part of the Open Source VHDL Verification Methodology here. There is a description and download link here.
http://www.synthworks.com/blog/osvvm/
It allows you to randomise much more than just a simple uniform distribution of floating point numbers. As well as isolating you from the state storage problem you have noted.
Regarding your specifics:
As I take it from the uniform function description, I should pass the two seeds from outside the function f because they are modified by the uniform function for the next call to uniform.
Yes, you should. Like this:
PROCESS
VARIABLE seed1, seed2: positive; -- Seed and state values for random generator
VARIABLE rand: real; -- Random real-number value in range 0 to 1.0
BEGIN
UNIFORM(seed1, seed2, rand);
So in your case, you'll have to pass those "state" variables into (and out of) your function too - which in practice means it has to be a procedure.
Or use the OSVVM library linked above which allows you to have a shared variable of protected type, which you can use from a variety of places. This keeps its own state "inside" the protected type.