Module: OrigenTesters::Timing
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/origen_testers/timing.rb
Defined Under Namespace
Classes: Timeset
Instance Method Summary collapse
- #before_timeset_change(options = {}) ⇒ Object
- #called_timesets ⇒ Object
-
#count(options = {}) ⇒ Object
This function can be used to generate a clock or some other repeating function that spans accross a range of vectors.
- #current_period_in_ns ⇒ Object (also: #current_period, #period)
- #current_timeset ⇒ Object (also: #timeset)
-
#cycles_to_time(cycles) ⇒ Object
Convert the supplied number of cycles to a time, based on the SoC defined cycle period.
-
#delay(cycles, options = {}) ⇒ Object
private
This should not be called directly, call via tester#wait.
- #max_repeat_loop ⇒ Object
-
#min_period_timeset ⇒ Object
Returns the timeset (a Timeset object) with the shortest period that has been encountered so far in the course of generating the current pattern.
- #min_repeat_loop ⇒ Object
-
#set_timeset(timeset, period_in_ns = nil) ⇒ Object
Set the timeset for the next vectors, this will remain in place until the next time this is called.
- #timeset_changed(timeset) ⇒ Object
-
#timing_toggled_pins ⇒ Object
When period levelling is enabled, vectors will be expanded like this: $tester.set_timeset(“fast”, 40) 2.cycles # fast 1 0 0 1 0 # fast 1 0 0 1 0 # Without levelling enabled $tester.set_timeset(“slow”, 80) 2.cycles # slow 1 0 0 1 0 # slow 1 0 0 1 0 # With levelling enabled $tester.set_timeset(“slow”, 80) 2.cycles # fast 1 0 0 1 0 # fast 1 0 0 1 0 # fast 1 0 0 1 0 # fast 1 0 0 1 0.
-
#wait(options = {}) ⇒ Object
Cause the pattern to wait.
Instance Method Details
#before_timeset_change(options = {}) ⇒ Object
180 181 |
# File 'lib/origen_testers/timing.rb', line 180 def before_timeset_change( = {}) end |
#called_timesets ⇒ Object
268 269 270 |
# File 'lib/origen_testers/timing.rb', line 268 def called_timesets @called_timesets ||= [] end |
#count(options = {}) ⇒ Object
This function can be used to generate a clock or some other repeating function that spans accross a range of vectors. The period of each cycle and the duration of the sequence are supplied via the following options:
-
:period_in_cycles
-
:period_in_ns
-
:period_in_us
-
:period_in_ms
-
:duration_in_cycles
-
:duration_in_ns
-
:duration_in_us
-
:duration_in_ms
If multiple definitions for either option are supplied then they will be added together.
Example
# Supply a clock pulse on :pinA for 100ms
$tester.count(:period_in_cycles => 10, :duration_in_ms => 100) do
$top.pin(:pinA).drive!(1)
$top.pin(:pinA).drive!(0)
end
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/origen_testers/timing.rb', line 312 def count( = {}) = { period_in_cycles: 0, period_in_ms: 0, period_in_us: 0, period_in_ns: 0, duration_in_cycles: 0, duration_in_ms: 0, duration_in_us: 0, duration_in_ns: 0 }.merge() period_cycles = [:period_in_cycles] + ms_to_cycles([:period_in_ms]) + us_to_cycles([:period_in_us]) + ns_to_cycles([:period_in_ns]) duration_cycles = [:duration_in_cycles] + ms_to_cycles([:duration_in_ms]) + us_to_cycles([:duration_in_us]) + ns_to_cycles([:duration_in_ns]) total = 0 while total < duration_cycles wait(time_in_cycles: period_cycles) yield # Return control back to caller total += period_cycles end end |
#current_period_in_ns ⇒ Object Also known as: current_period, period
272 273 274 275 276 277 278 |
# File 'lib/origen_testers/timing.rb', line 272 def current_period_in_ns if @timeset @timeset.period_in_ns else fail 'No timeset has been specified yet!' end end |
#current_timeset ⇒ Object Also known as: timeset
282 283 284 |
# File 'lib/origen_testers/timing.rb', line 282 def current_timeset @timeset end |
#cycles_to_time(cycles) ⇒ Object
Convert the supplied number of cycles to a time, based on the SoC defined cycle period
288 289 290 |
# File 'lib/origen_testers/timing.rb', line 288 def cycles_to_time(cycles) # :nodoc: (cycles * current_period_in_ns).to_f / 1_000_000_000 end |
#delay(cycles, options = {}) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This should not be called directly, call via tester#wait
245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/origen_testers/timing.rb', line 245 def delay(cycles, = {}) (cycles / max_repeat_loop).times do if block_given? yield .merge(repeat: max_repeat_loop) else cycle(.merge(repeat: max_repeat_loop)) end end if block_given? yield .merge(repeat: (cycles % max_repeat_loop)) else cycle(.merge(repeat: (cycles % max_repeat_loop))) end end |
#max_repeat_loop ⇒ Object
260 261 262 |
# File 'lib/origen_testers/timing.rb', line 260 def max_repeat_loop @max_repeat_loop || 65_535 end |
#min_period_timeset ⇒ Object
Returns the timeset (a Timeset object) with the shortest period that has been encountered so far in the course of generating the current pattern.
A tester object is re-instantiated at the start of every pattern which will reset this variable.
163 164 165 |
# File 'lib/origen_testers/timing.rb', line 163 def min_period_timeset @min_period_timeset end |
#min_repeat_loop ⇒ Object
264 265 266 |
# File 'lib/origen_testers/timing.rb', line 264 def min_repeat_loop @min_repeat_loop end |
#set_timeset(timeset, period_in_ns = nil) ⇒ Object
Set the timeset for the next vectors, this will remain in place until the next time this is called.
$tester.set_timeset("bist_25mhz", 40)
This method also accepts a block in which case the contained vectors will generate with the supplied timeset and subsequent vectors will return to the previous timeset automatically.
$tester.set_timeset("bist_25mhz", 40) do
$tester.cycle
end
The arguments can also be supplied as a single array, or not at all. In the latter case the existing timeset will simply be preserved. This is useful if you have timesets that can be conditionally set based on the target.
# Target 1
$soc.readout_timeset = ["readout", 120]
# Target 2
$soc.readout_timeset = false
# This code is compatible with both targets, in the first case the timeset will switch
# over, in the second case the existing timeset will be preserved.
$tester.set_timeset($soc.readout_timeset) do
$tester.cycle
end
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/origen_testers/timing.rb', line 130 def set_timeset(timeset, period_in_ns = nil) if timeset.is_a?(Array) timeset, period_in_ns = timeset[0], timeset[1] end timeset ||= @timeset unless timeset.is_a?(Timeset) fail 'You must supply a period_in_ns argument to set_timeset' unless period_in_ns timeset = Timeset.new(name: timeset.to_s.chomp, period_in_ns: period_in_ns) end called_timesets << timeset unless called_timesets.map(&:name).include?(timeset.name) if @min_period_timeset @min_period_timeset = timeset if timeset.shorter_period_than?(@min_period_timeset) else @min_period_timeset = timeset end if block_given? original = @timeset timeset_changed(timeset) @timeset = timeset yield timeset_changed(original) @timeset = original else timeset_changed(timeset) @timeset = timeset end end |
#timeset_changed(timeset) ⇒ Object
167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/origen_testers/timing.rb', line 167 def timeset_changed(timeset) if last_vector && last_vector.timeset != timeset change = { old: last_vector.timeset, new: timeset } # Suppress any duplicate calls if !@_last_timeset_change || (@_last_timeset_change[:new] != change[:new] && @_last_timeset_change[:old] != change[:old]) before_timeset_change(change) end @_last_timeset_change = change end end |
#timing_toggled_pins ⇒ Object
When period levelling is enabled, vectors will be expanded like this:
$tester.set_timeset("fast", 40)
2.cycles # fast 1 0 0 1 0
# fast 1 0 0 1 0
# Without levelling enabled
$tester.set_timeset("slow", 80)
2.cycles # slow 1 0 0 1 0
# slow 1 0 0 1 0
# With levelling enabled
$tester.set_timeset("slow", 80)
2.cycles # fast 1 0 0 1 0
# fast 1 0 0 1 0
# fast 1 0 0 1 0
# fast 1 0 0 1 0
The overall time of the levelled/expanded vectors matches that of the unlevelled case. i.e. 4 cycles at fast speed (4 * 40ns = 160ns) is equivalent to 2 cycles at slow speed (2 * 80ns = 160ns).
However, what if pin 1 in the example above was a clk pin where the 1 -> 0 transition was handled by the timing setup for that pin. In that case the levelled code is no longer functionally correct since it contains 4 clock pulses while the unlevelled code only has 2.
Such pins can be specified via this attribute and the levelling logic will then automatically adjust the drive state to keep the number of pulses correct. It would automatically adjust to the alternative logic state where 0 means ‘on’ and 1 means ‘off’ if applicable.
$tester.timing_toggled_pins << $dut.pin(:tclk) # This is pin 1
$tester.set_timeset("fast", 40)
2.cycles # fast 1 0 0 1 0
# fast 1 0 0 1 0
# Without levelling enabled
$tester.set_timeset("slow", 80)
2.cycles # slow 1 0 0 1 0
# slow 1 0 0 1 0
# With levelling enabled
$tester.set_timeset("slow", 80)
2.cycles # fast 1 0 0 1 0
# fast 0 0 0 1 0
# fast 1 0 0 1 0
# fast 0 0 0 1 0
Multiple pins an be specified like this:
$tester.timing_toggled_pins = [$dut.pin(:tclk), $dut.pin(:clk)] # Overrides any pins added elsewhere
$tester.timing_toggled_pins << [$dut.pin(:tclk), $dut.pin(:clk)] # In addition to any pins added elsewhere
97 98 99 100 101 |
# File 'lib/origen_testers/timing.rb', line 97 def timing_toggled_pins @timing_toggled_pins ||= [] @timing_toggled_pins.flatten! @timing_toggled_pins end |
#wait(options = {}) ⇒ Object
Cause the pattern to wait. The following options are available to help you specify the time to wait:
-
:cycles - delays specified in raw cycles, the test model is responsible for translating this into a sequence of valid repeat statements
-
:time_in_ns - time specified in nano-seconds
-
:time_in_us - time specified in micro-seconds
-
:time_in_ms - time specified in milli-seconds
-
:time_in_s - time specified in seconds
If more than one option is supplied they will get added together to give a final delay time expressed in cycles.
Examples
$tester.wait(cycles: 100, time_in_ns: 200) # Wait for 100 cycles + 200ns
This method can also be used to trigger a match loop in which case the supplied time becomes the time out for the match. See the J750#match method for full details of the available options.
$tester.wait(match: true, state: :high, pin: $dut.pin(:done), time_in_ms: 500)
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/origen_testers/timing.rb', line 198 def wait( = {}) = { cycles: 0, time_in_cycles: 0, time_in_us: 0, time_in_ns: 0, time_in_ms: 0, time_in_s: 0, match: false, # Set to true to invoke a match loop where the supplied delay # will become the timeout duration }.merge() cycles = 0 cycles += [:cycles] + [:time_in_cycles] cycles += s_to_cycles([:time_in_s]) cycles += ms_to_cycles([:time_in_ms]) cycles += us_to_cycles([:time_in_us]) cycles += ns_to_cycles([:time_in_ns]) time = cycles * current_period_in_ns # Total delay in ns case when time < 1000 # When less than 1us cc "Wait for #{'a maximum of ' if [:match]}#{time}ns" when time < 1_000_000 # When less than 1ms cc "Wait for #{'a maximum of ' if [:match]}#{(time.to_f / 1000).round(1)}us" # Display delay in us when time < 1_000_000_000 # When less than 1s cc "Wait for #{'a maximum of ' if [:match]}#{(time.to_f / 1_000_000).round(1)}ms" else cc "Wait for #{'a maximum of ' if [:match]}%.2fs" % (time.to_f / 1_000_000_000) end if cycles > 0 # Allow this function to be called with 0 in which case it will just return if [:match] if block_given? match_block(cycles, ) { yield } else match([:pin], [:state], cycles, ) end else delay(cycles) end end end |