Module: Origen::Tester::Timing

Included in:
Origen::Tester
Defined in:
lib/origen/tester/timing.rb

Defined Under Namespace

Classes: Timeset

Instance Method Summary (collapse)

Instance Method Details

- (Object) before_timeset_change(_options = {})



77
78
# File 'lib/origen/tester/timing.rb', line 77

def before_timeset_change(_options = {})
end

- (Object) called_timesets



189
190
191
# File 'lib/origen/tester/timing.rb', line 189

def called_timesets
  @called_timesets ||= []
end

- (Object) count(options = {})

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


233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/origen/tester/timing.rb', line 233

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

- (Object) current_period_in_ns Also known as: current_period, period



193
194
195
196
197
198
199
# File 'lib/origen/tester/timing.rb', line 193

def current_period_in_ns
  if @timeset
    @timeset.period_in_ns
  else
    fail 'No timeset has been specified yet!'
  end
end

- (Object) current_timeset Also known as: timeset



203
204
205
# File 'lib/origen/tester/timing.rb', line 203

def current_timeset
  @timeset
end

- (Object) cycles_to_ms(cycles)

:nodoc:



180
181
182
# File 'lib/origen/tester/timing.rb', line 180

def cycles_to_ms(cycles) # :nodoc:
  ((cycles.to_f * current_period_in_ns) / (1000 * 1000)).ceil
end

- (Object) cycles_to_time(cycles)

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



209
210
211
# File 'lib/origen/tester/timing.rb', line 209

def cycles_to_time(cycles) # :nodoc:
  (cycles * current_period_in_ns).to_f / 1_000_000_000
end

- (Object) cycles_to_ts(cycles)

Cycles to tenths of a second



185
186
187
# File 'lib/origen/tester/timing.rb', line 185

def cycles_to_ts(cycles) # :nodoc:
  ((cycles.to_f * current_period_in_ns) / (1000 * 1000 * 100)).ceil
end

- (Object) cycles_to_us(cycles)

:nodoc:



176
177
178
# File 'lib/origen/tester/timing.rb', line 176

def cycles_to_us(cycles) # :nodoc:
  ((cycles.to_f * current_period_in_ns) / (1000)).ceil
end

- (Object) delay(cycles, options = {})

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



141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/origen/tester/timing.rb', line 141

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

- (Object) max_repeat_loop



156
157
158
# File 'lib/origen/tester/timing.rb', line 156

def max_repeat_loop
  @max_repeat_loop || 65_535
end

- (Object) ms_to_cycles(time)

:nodoc:



164
165
166
# File 'lib/origen/tester/timing.rb', line 164

def ms_to_cycles(time) # :nodoc:
  ((time.to_f) * 1000 * 1000 / current_period_in_ns).to_int
end

- (Object) ns_to_cycles(time)

:nodoc:



172
173
174
# File 'lib/origen/tester/timing.rb', line 172

def ns_to_cycles(time) # :nodoc:
  (time.to_f / current_period_in_ns).to_int
end

- (Object) s_to_cycles(time)

:nodoc:



160
161
162
# File 'lib/origen/tester/timing.rb', line 160

def s_to_cycles(time) # :nodoc:
  ((time.to_f) * 1000 * 1000 * 1000 / current_period_in_ns).to_int
end

- (Object) set_timeset(timeset, period_in_ns = nil)

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


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/origen/tester/timing.rb', line 41

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 block_given?
    original = @timeset
    timeset_changed(timeset)
    @timeset = timeset
    yield
    timeset_changed(original)
    @timeset = original
  else
    timeset_changed(timeset)
    @timeset = timeset
  end
end

- (Object) timeset_changed(timeset)



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/origen/tester/timing.rb', line 64

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

- (Object) us_to_cycles(time)

:nodoc:



168
169
170
# File 'lib/origen/tester/timing.rb', line 168

def us_to_cycles(time) # :nodoc:
  ((time.to_f * 1000) / current_period_in_ns).to_int
end

- (Object) wait(options = {})

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 => $top.pin(:done), :time_in_ms => 500)


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/origen/tester/timing.rb', line 95

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