Module: OrigenTesters::Timing::TimingAPI

Included in:
OrigenTesters::Timing
Defined in:
lib/origen_testers/timing/timing_api.rb

Instance Method Summary collapse

Instance Method Details

#before_timeset_change(options = {}) ⇒ Object


109
110
# File 'lib/origen_testers/timing/timing_api.rb', line 109

def before_timeset_change(options = {})
end

#called_timesetsArray Also known as: called_timesets_by_instance

Returns any timesets that have been called during this execution.

Returns:

  • (Array)

    Array of OrigenTesters::Timing::Timeset objects that have been used so far.


209
210
211
# File 'lib/origen_testers/timing/timing_api.rb', line 209

def called_timesets
  OrigenTesters::Timing.called_timesets
end

#called_timesets_by_nameArray

Similar to #called_timesets, but returns the name of the timesets instead.

Returns:

  • (Array)

    Array of names corresponding to the timesets that have been used so far.


216
217
218
# File 'lib/origen_testers/timing/timing_api.rb', line 216

def called_timesets_by_name
  OrigenTesters::Timing.called_timesets_by_name
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

256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/origen_testers/timing/timing_api.rb', line 256

def count(options = {})
  options = { 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(options)

  period_cycles = options[:period_in_cycles] + ms_to_cycles(options[:period_in_ms]) +
                  us_to_cycles(options[:period_in_us]) + ns_to_cycles(options[:period_in_ns])

  duration_cycles = options[:duration_in_cycles] + ms_to_cycles(options[:duration_in_ms]) +
                    us_to_cycles(options[:duration_in_us]) + ns_to_cycles(options[: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_nsObject Also known as: current_period, period


220
221
222
# File 'lib/origen_testers/timing/timing_api.rb', line 220

def current_period_in_ns
  OrigenTesters::Timing.current_period_in_ns
end

#current_timesetObject Also known as: timeset


226
227
228
# File 'lib/origen_testers/timing/timing_api.rb', line 226

def current_timeset
  OrigenTesters::Timing.current_timeset
end

#cycles_to_time(cycles) ⇒ Object

Convert the supplied number of cycles to a time, based on the SoC defined cycle period


232
233
234
# File 'lib/origen_testers/timing/timing_api.rb', line 232

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

See Also:

  • Timing#wait

184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/origen_testers/timing/timing_api.rb', line 184

def delay(cycles, options = {})
  (cycles / max_repeat_loop).times do
    if block_given?
      yield options.merge(repeat: max_repeat_loop)
    else
      cycle(options.merge(repeat: max_repeat_loop))
    end
  end
  if block_given?
    yield options.merge(repeat: (cycles % max_repeat_loop))
  else
    cycle(options.merge(repeat: (cycles % max_repeat_loop)))
  end
end

#max_repeat_loopObject


199
200
201
# File 'lib/origen_testers/timing/timing_api.rb', line 199

def max_repeat_loop
  @max_repeat_loop || 65_535
end

#min_period_timesetObject

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.


105
106
107
# File 'lib/origen_testers/timing/timing_api.rb', line 105

def min_period_timeset
  OrigenTesters::Timing.min_period_timeset
end

#min_repeat_loopObject


203
204
205
# File 'lib/origen_testers/timing/timing_api.rb', line 203

def min_repeat_loop
  @min_repeat_loop
end

#period_in_nsObject

Returns the current period in ns, or nil, if no timeset has been set.


113
114
115
# File 'lib/origen_testers/timing/timing_api.rb', line 113

def period_in_ns
  OrigenTesters::Timing.period_in_ns
end

#period_in_secsObject Also known as: period_in_seconds


117
118
119
# File 'lib/origen_testers/timing/timing_api.rb', line 117

def period_in_secs
  OrigenTesters::Timing.period_in_ns
end

#set_timeset(timeset, period_in_ns = nil, &block) ⇒ Object Also known as: with_timeset

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

87
88
89
# File 'lib/origen_testers/timing/timing_api.rb', line 87

def set_timeset(timeset, period_in_ns = nil, &block)
  OrigenTesters::Timing.set_timeset(timeset, period_in_ns, &block)
end

#timeset?(t) ⇒ Boolean

Returns:

  • (Boolean)

96
97
98
# File 'lib/origen_testers/timing/timing_api.rb', line 96

def timeset?(t)
  OrigenTesters::Timing.timeset?(t)
end

#timesetsObject


92
93
94
# File 'lib/origen_testers/timing/timing_api.rb', line 92

def timesets
  OrigenTesters::Timing.timesets
end

#timing_toggled_pinsObject

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

See Also:

  • Timing#level_period

54
55
56
57
58
# File 'lib/origen_testers/timing/timing_api.rb', line 54

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)

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/origen_testers/timing/timing_api.rb', line 137

def wait(options = {})
  options = {
    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(options)

  cycles = 0
  cycles += options[:cycles] + options[:time_in_cycles]
  cycles += s_to_cycles(options[:time_in_s])
  cycles += ms_to_cycles(options[:time_in_ms])
  cycles += us_to_cycles(options[:time_in_us])
  cycles += ns_to_cycles(options[: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 options[:match]}#{time}ns"
    when time < 1_000_000                   # When less than 1ms
      cc "Wait for #{'a maximum of ' if options[: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 options[:match]}#{(time.to_f / 1_000_000).round(1)}ms"
    else
      cc "Wait for #{'a maximum of ' if options[: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 options[:match]
      if block_given?
        match_block(cycles, options) { yield }
      else
        match(options[:pin], options[:state], cycles, options)
      end
    else
      delay(cycles)
    end
  end
end