Barrier synchronization with integer_barrier
May 30, 2023 at 02:54 #2207JasonMember
I want to make sure I understand what is going on “under the hood” when using integer_barrier type barrier sync signal (as is done in the AXI4 testbenches). From what I have gleaned from reading “VHDL-2008 Just the New Stuff”, the simulator will automagically create an array of integers to pass into the resolution function resolved_barrier because that is the function name in the integer_barrier subtype declaration and the function is defined to receive an integer_vector and return an integer. Is this all just per VHDL-2008 or is there more to the story? it might be nice to add more details on this subject in the documentation of the barrier sync for folks like me who are not as familiar with some of the more esoteric features of the language. Thank you.
p.s. I noticed that the integer_barrier signal ‘TestDone’ is not visible in the object window of my simulator (Riviera-Pro). I wonder if this is to be expected or if it is an issue with the tool.May 30, 2023 at 04:33 #2208Jim LewisMember
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 ; begin 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 begin 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).May 30, 2023 at 13:49 #2211JasonMember
Thank you for this detailed response – very informative.
I found the TestDone signal in my simulator (was looking for it in the wrong part of the hierarchy) and it behaves as expected. FYI I am only using SetDebugMode and did not need to use SetInteractiveMode.May 30, 2023 at 14:35 #2212Jim LewisMember
Agreed that SetDebugMode is enough for what you are doing. SetInteractiveMode = SetDebugMode + SetLogSignals + Stop Simulation when analyze or simulate error occurs.
I use SetInteractiveMode false when running a set of simulations in CI or as a regression as I want to see results from all tests, but SetInteractiveMode when debugging.
- You must be logged in to reply to this topic.