Reply To: Barrier synchronization with integer_barrier
Resolution functions are a VHDL-1987 feature. So Ashenden’s VHDL Designers Guide should have a good description of them. I will describe them briefly here too.
In VHDL-2008, element based resolution functions were extended to support array objects. So std_logic_vector is now defined as:
subtype std_logic_vector is (resolved) std_ulogic_vector ;
What is cool about this is that types that are related by a resolution function convert automatically – meaning that you can now use std_logic_vector and std_ulogic_vector interchangeably (provided you do not have multiple drivers and require std_logic_vector).
To create a tristate using std_logic, you drive a ‘Z’ and it works exactly as a tristate does. To use barrier synchronization using type integer_barrier, you create one signal name per barrier (synchronization point) and call WaitForBarrier at the barrier synchronization point. The integer_barrier signal can be initialized, but it is not required and most certainly do not initialize it to 0 (as the value 0 releases OSVVM’s integer based barriers).
That said, many (myself included) want to understand something before using it, so the long answer is below.
Every concurrent source of a signal (assignment, output parameter of procedure, output port of an entity), creates a driver on that signal. WaitForBarrier has its signal parameter as an inout, so calling WaitForBarrier puts a driver on that signal. When a signal, such as TestDone, has multiple drivers on it, it must have a resolution function associated with it. The resolution function is called with all of the individual values being driven and calculates the effective value of the signal. Hence, the input to the resolution function is an array of the type you want to resolve. Integer_barrier is a resolved integer type, and hence, the input to resolved_barrier is integer_vector – note there is nothing special about integer_vector, any array type of integer would be fine.
The code for resolved barrier is:
function resolved_barrier ( s : integer_vector ) return integer is
variable result : integer := 0 ;
for i in s'RANGE loop
if s(i) /= 0 then
result := result + 1;
end if ;
end loop ;
return result ;
end function resolved_barrier ;
Very simply, for each non-zero input, resolved_barrier adds one to the signal value.
In WaitForBarrier with type integer_barrier (shown below), non-zero means the barrier is blocked and waiting. When WaitForBarrier is called, it assigns a zero to the barrier signal. After assigning the value zero to the barrier signal, WaitForBarrier waits until the barrier signal goes to 0. Hence, when a barrier is blocked, the count indicates how many processes have not reached the barrier yet. After finding the barrier signal at 0, the remaining steps of WaitForBarrier reset the barrier to allow the barrier signal to be used again (but keep in mind, my recommendation is to use each barrier signal one once unless you really understand drivers as on a bad day, there will be frustrating lessons there).
procedure WaitForBarrier ( signal Sig : InOut integer ) is
Sig <= 0 ;
-- Wait until all processes set Sig to 0
-- Level check not necessary since last value /= 0 yet
wait until Sig = 0 ;
-- Deactivate and propagate to allow back to back calls
Sig <= 1 ;
wait for 0 ns ;
end procedure WaitForBarrier ;
Hopefully this clarifies how this works – at least a little. Ashenden’s book, A Designers Guide to VHDL, or Bhasker’s book, A VHDL Primer, should have a good description of resolution functions. Also feel free to ask clarifying questions.
You should be able to display the TestDone signal. Sometimes you have to set the optimization switches so that the simulator will not remove some signals from visibility (an optimization thing). In OSVVM *.pro scripting, in both Aldec’s and Siemen’s tools you can do
and it will set your simulator to not optimize away signals and to log all signals while the simulation is running so they can be displayed while debugging after the simulation has completed. Note SetInteractive true, especially the log of all signals will likely slow your simulation down, but it is very helpful if you are debugging.
There are additional examples of resolution functions in OsvvmLibraries/osvvm/ResolutionPkg.vhd (uses maximum as a resolution function – this is used in OSVVM transaction interfaces) and OsvvmLibraries/Common/AddressBusTransactionPkg.vhd (in resolving the operation type, special enumerations NOT_DRIVEN and MULTIPLER_DRIVER_DETECT are used to make sure there is only one driver on the Operation field of the record – a common mistake due to cut and paste errors).