Class: OrigenTesters::SmartestBasedTester::Base
- Inherits:
-
Object
- Object
- OrigenTesters::SmartestBasedTester::Base
- Includes:
- VectorBasedTester
- Defined in:
- lib/origen_testers/smartest_based_tester/base.rb,
lib/origen_testers/smartest_based_tester/base/flow.rb,
lib/origen_testers/smartest_based_tester/base/generator.rb,
lib/origen_testers/smartest_based_tester/base/test_suite.rb,
lib/origen_testers/smartest_based_tester/base/test_method.rb,
lib/origen_testers/smartest_based_tester/base/test_suites.rb,
lib/origen_testers/smartest_based_tester/base/test_methods.rb,
lib/origen_testers/smartest_based_tester/base/pattern_master.rb,
lib/origen_testers/smartest_based_tester/base/pattern_compiler.rb,
lib/origen_testers/smartest_based_tester/base/test_methods/ac_tml.rb,
lib/origen_testers/smartest_based_tester/base/test_methods/dc_tml.rb,
lib/origen_testers/smartest_based_tester/base/test_methods/limits.rb,
lib/origen_testers/smartest_based_tester/base/test_methods/base_tml.rb,
lib/origen_testers/smartest_based_tester/base/test_methods/custom_tml.rb
Direct Known Subclasses
Defined Under Namespace
Modules: Generator Classes: Flow, PatternCompiler, PatternMaster, TestMethod, TestMethods, TestSuite, TestSuites
Instance Method Summary collapse
- #before_timeset_change(options = {}) ⇒ Object
-
#call_subroutine(name, options = {}) ⇒ Object
Call a subroutine.
-
#called_subroutines ⇒ Object
Returns an array of subroutines called while generating the current pattern.
-
#end_subroutine(_cond = false) ⇒ Object
Ends the current subroutine that was started with a previous call to start_subroutine.
-
#format_vector(vec) ⇒ Object
This is an internal method use by Origen which returns a fully formatted vector You can override this if you wish to change the output formatting at vector level.
-
#freq_count(_pin, options = {}) ⇒ Object
Do a frequency measure.
-
#handshake(options = {}) ⇒ Object
Handshake with the tester.
-
#initialize ⇒ Base
constructor
Returns a new J750 instance, normally there would only ever be one of these assigned to the global variable such as $tester by your target: $tester = J750.new.
-
#local_subroutines ⇒ Object
Returns an array of subroutines created by the current pattern.
-
#loop_vectors(name = nil, number_of_loops = 1, _global = false) ⇒ Object
(also: #loop_vector)
Add a loop to the pattern.
-
#match(pin, state, timeout_in_cycles, options = {}) ⇒ Object
Generates a match loop on up to two pins.
-
#pattern_footer(options = {}) ⇒ Object
An internal method called by Origen to generate the pattern footer.
-
#pattern_header(options = {}) ⇒ Object
An internal method called by Origen to create the pattern header.
-
#propagation_delay ⇒ Object
Returns the number of cycles to wait for any fails to propagate through the pipeline based on the current timeset.
-
#repeat_previous ⇒ Object
All vectors generated with the supplied block will have all pins set to the repeat previous state.
-
#start_subroutine(name) ⇒ Object
Start a subroutine.
-
#store(*pins) ⇒ Object
(also: #capture)
Capture the pin data from a vector to the tester.
-
#store_next_cycle(*pins) ⇒ Object
Capture the next vector generated to HRAM.
Methods included from VectorBasedTester
Constructor Details
#initialize ⇒ Base
Returns a new J750 instance, normally there would only ever be one of these assigned to the global variable such as $tester by your target:
$tester = J750.new
9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 9 def initialize @max_repeat_loop = 65_535 @min_repeat_loop = 17 @pat_extension = 'avc' @compress = true # @support_repeat_previous = true @match_entries = 10 @name = 'v93k' @comment_char = '#' @level_period = true end |
Instance Method Details
#before_timeset_change(options = {}) ⇒ Object
418 419 420 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 418 def before_timeset_change( = {}) microcode "SQPG CTIM #{[:new].name};" unless level_period? end |
#call_subroutine(name, options = {}) ⇒ Object
Call a subroutine.
This calls a subroutine immediately following previous vector, it does not generate a new vector.
Subroutines should always be called through this method as it ensures a running log of called subroutines is maintained and which then gets output in the pattern header to import the right dependencies.
An offset option is available to make the call on earlier vectors.
Repeated calls to the same subroutine will automatically be compressed unless option :suppress_repeated_calls is supplied and set to false. This means that for the common use case of calling a subroutine to implement an overlay the subroutine can be called for every bit that has the overlay and the pattern will automatically generate correctly.
Examples
$tester.call_subroutine("mysub")
$tester.call_subroutine("my_other_sub", :offset => -1)
145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 145 def call_subroutine(name, = {}) = { offset: 0, suppress_repeated_calls: true }.merge() called_subroutines << name.to_s.chomp unless called_subroutines.include?(name.to_s.chomp) || @inhibit_vectors code = "SQPG JSUB #{name};" if ![:suppress_repeated_calls] || last_object != code microcode code, offset: ([:offset] * -1) end end |
#called_subroutines ⇒ Object
Returns an array of subroutines called while generating the current pattern
373 374 375 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 373 def called_subroutines @called_subroutines ||= [] end |
#end_subroutine(_cond = false) ⇒ Object
Ends the current subroutine that was started with a previous call to start_subroutine
121 122 123 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 121 def end_subroutine(_cond = false) Pattern.close call_shutdown_callbacks: false, subroutine: true end |
#format_vector(vec) ⇒ Object
This is an internal method use by Origen which returns a fully formatted vector You can override this if you wish to change the output formatting at vector level
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 384 def format_vector(vec) timeset = vec.timeset ? "#{vec.timeset.name}" : '' pin_vals = vec.pin_vals ? "#{vec.pin_vals} ;" : '' if vec.repeat # > 1 microcode = "R#{vec.repeat}" else microcode = vec.microcode ? vec.microcode : '' end if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments) comment = " # #{vec.number}:#{vec.cycle} #{vec.inline_comment}" else comment = vec.inline_comment.empty? ? '' : " # #{vec.inline_comment}" end "#{microcode.ljust(25)}#{timeset.ljust(27)}#{pin_vals}#{comment}" end |
#freq_count(_pin, options = {}) ⇒ Object
Do a frequency measure.
Examples
$tester.freq_count($top.pin(:d_out)) # Freq measure on pin "d_out"
173 174 175 176 177 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 173 def freq_count(_pin, = {}) = { }.merge() Pattern.split() end |
#handshake(options = {}) ⇒ Object
Handshake with the tester.
Examples
$tester.handshake # Pass control to the tester for a measurement
163 164 165 166 167 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 163 def handshake( = {}) = { }.merge() Pattern.split() end |
#local_subroutines ⇒ Object
Returns an array of subroutines created by the current pattern
378 379 380 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 378 def local_subroutines # :nodoc: @local_subroutines ||= [] end |
#loop_vectors(name = nil, number_of_loops = 1, _global = false) ⇒ Object Also known as: loop_vector
Add a loop to the pattern.
Pass in the number of times to execute it, all vectors generated by the given block will be captured in the loop.
Examples
$tester.loop_vectors 3 do # Do this 3 times...
$tester.cycle
some_other_method_to_generate_vectors
end
For compatibility with the J750 you can supply a name as the first argument and that will simply be ignored when generated for the V93K tester…
$tester.loop_vectors "my_loop", 3 do # Do this 3 times...
$tester.cycle
some_other_method_to_generate_vectors
end
321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 321 def loop_vectors(name = nil, number_of_loops = 1, _global = false) # The name argument is present to maych J750 API, sort out the unless name.is_a?(String) name, number_of_loops, global = nil, name, number_of_loops end if number_of_loops > 1 microcode "SQPG LBGN #{number_of_loops};" yield microcode 'SQPG LEND;' else yield end end |
#match(pin, state, timeout_in_cycles, options = {}) ⇒ Object
Generates a match loop on up to two pins.
This method is not really intended to be called directly, rather you should call via Tester#wait e.g. $tester.wait(:match => true).
The timeout should be provided in cycles, however when called via the wait method the time-based helpers (time_in_us, etc) will be converted to cycles for you. The following options are available to tailor the match loop behavior, defaults in parenthesis:
-
:pin - The pin object to match on (required)
-
:state - The pin state to match on, :low or :high (required)
-
:check_for_fails (false) - Flushes the pipeline and checks for fails prior to the match (to allow binout of fails encountered before the match)
-
:pin2 (nil) - Optionally supply a second pin to match on
-
:state2 (nil) - State for the second pin (required if :pin2 is supplied)
-
:force_fail_on_timeout (true) - Force a vector mis-compare if the match loop times out
Examples
$tester.wait(:match => true, :time_in_us => 5000, :pin => $top.pin(:done), :state => :high)
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 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 198 def match(pin, state, timeout_in_cycles, = {}) = { check_for_fails: false, pin2: false, state2: false, global_loops: false, generate_subroutine: false, force_fail_on_timeout: true }.merge() # Ensure the match pins are don't care by default pin.dont_care [:pin2].dont_care if [:pin2] # Single condition loops are simple if ![:pin2] # Use the counted match loop (rather than timed) which is recommended in the V93K docs for new applications # No pre-match failure handling is required here because the system will cleanly record failure info # for this kind of match loop cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}" # Need to ensure at least 8 cycles with no compares before entering 8.cycles number_of_loops = (timeout_in_cycles.to_f / 72).ceil # This seems to be a limit on the max MACT value, so account for longer times by expanding # the wait loop if number_of_loops > 262_144 mrpt = ((timeout_in_cycles.to_f / 262_144) - 8).ceil mrpt = Math.sqrt(mrpt).ceil mrpt += (8 - (mrpt % 8)) # Keep to a multiple of 8, but round up to be safe number_of_loops = 262_144 else mrpt = 8 end microcode "SQPG MACT #{number_of_loops};" # Strobe the pin for the required state state == :low ? pin.expect_lo : pin.expect_hi # Always do 8 vectors here as this allows reconstruction of test results if multiple loops # are called in a pattern 8.cycles pin.dont_care # Now do the wait loop, mrpt should always be a multiple of 8 microcode "SQPG MRPT #{mrpt};" mrpt.times do cycle(dont_compress: true) end microcode 'SQPG PADDING;' 8.cycles else # For two pins do something more like the J750 approach where branching based on miscompares is used # to keep the loop going cc "for the #{pin.name.upcase} pin to go #{state.to_s.upcase}" cc "or the #{[:pin2].name.upcase} pin to go #{[:state2].to_s.upcase}" if [:check_for_fails] cc 'Return preserving existing errors if the pattern has already failed before arriving here' cycle(repeat: propagation_delay) microcode 'SQPG RETC 1 1;' end number_of_loops = (timeout_in_cycles.to_f / ((propagation_delay * 2) + 2)).ceil loop_vectors number_of_loops do # Check pin 1 cc "Check if #{pin.name.upcase} is #{state.to_s.upcase} yet" state == :low ? pin.expect_lo! : pin.expect_hi! pin.dont_care cc 'Wait for failure to propagate' cycle(repeat: propagation_delay) cc 'Exit match loop if pin has matched (no error), otherwise clear error and remain in loop' microcode 'SQPG RETC 0 0;' # Check pin 2 cc "Check if #{[:pin2].name.upcase} is #{[:state2].to_s.upcase} yet" [:state2] == :low ? [:pin2].expect_lo! : [:pin2].expect_hi! [:pin2].dont_care cc 'Wait for failure to propagate' cycle(repeat: propagation_delay) cc 'Exit match loop if pin has matched (no error), otherwise clear error and remain in loop' microcode 'SQPG RETC 0 0;' end if [:force_fail_on_timeout] cc 'To get here something has gone wrong, strobe again to force a pattern failure' state == :low ? pin.expect_lo : pin.expect_hi [:state2] == :low ? [:pin2].expect_lo : [:pin2].expect_hi if [:pin2] cycle pin.dont_care [:pin2].dont_care if [:pin2] end end end |
#pattern_footer(options = {}) ⇒ Object
An internal method called by Origen to generate the pattern footer
368 369 370 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 368 def ( = {}) microcode 'SQPG STOP;' unless [:subroutine] end |
#pattern_header(options = {}) ⇒ Object
An internal method called by Origen to create the pattern header
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 337 def pattern_header( = {}) = { }.merge() pin_list = ordered_pins.map do |p| if Origen.app.pin_pattern_order.include?(p.id) # specified name overrides pin name if (p.is_a?(Origen::Pins::PinCollection)) || p.id != p.name p.id.to_s # groups or aliases can be lower case else p.id.to_s.upcase # pins must be uppercase end else if (p.is_a?(Origen::Pins::PinCollection)) || p.id != p.name p.name.to_s # groups or aliases can be lower case else p.name.to_s.upcase # pins must be uppercase end end end.join(' ') microcode "FORMAT #{pin_list};" if ordered_pins.size > 0 max_pin_name_length = ordered_pins.map(&:name).max { |a, b| a.length <=> b.length }.length pin_widths = ordered_pins.map { |p| p.size - 1 } max_pin_name_length.times do |i| cc((' ' * 50) + ordered_pins.map.with_index { |p, x| ((p.name[i] || ' ') + ' ' * pin_widths[x]).gsub('_', '-') }.join(' ')) end end end |
#propagation_delay ⇒ Object
Returns the number of cycles to wait for any fails to propagate through the pipeline based on the current timeset
293 294 295 296 297 298 299 300 301 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 293 def propagation_delay # From 'Calculating the buffer cycles for JMPE and RETC (and match loops)' in SmarTest docs data_queue_buffer = (([105, 64 + ((125 + current_period_in_ns - 1) / current_period_in_ns).ceil].min + 3) * 8) + 72 # Don't know how to calculate at runtime, hardcoding these to some default values for now number_of_sites = 128 sclk_period = 40 prop_delay_buffer = 195 + ((2 * number_of_sites + 3) * (sclk_period / 2)) data_queue_buffer + prop_delay_buffer end |
#repeat_previous ⇒ Object
All vectors generated with the supplied block will have all pins set to the repeat previous state. Any pins that are changed state within the block will still update to the supplied value.
Example
# All pins except invoke will be assigned the repeat previous code
# in the generated vector. On completion of the block they will
# return to their previous state, except for invoke which will
# retain the value assigned within the block.
$tester.repeat_previous do
$top.pin(:invoke).drive(1)
$tester.cycle
end
412 413 414 415 416 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 412 def repeat_previous Origen.app.pin_map.each { |_id, pin| pin.repeat_previous = true } yield Origen.app.pin_map.each { |_id, pin| pin.repeat_previous = false } end |
#start_subroutine(name) ⇒ Object
Start a subroutine.
Generates a global subroutine label. Global is used to adhere to the best practice of containing all subroutines in dedicated patterns, e.g. global_subs.atp
Examples
$tester.start_subroutine("wait_for_done")
< generate your subroutine vectors here >
$tester.end_subroutine
114 115 116 117 118 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 114 def start_subroutine(name) local_subroutines << name.to_s.chomp unless local_subroutines.include?(name.to_s.chomp) || @inhibit_vectors # name += "_subr" unless name =~ /sub/ Pattern.open name: name, call_startup_callbacks: false, subroutine: true end |
#store(*pins) ⇒ Object Also known as: capture
Capture the pin data from a vector to the tester.
This method uses the Digital Capture feature (Selective mode) of the V93000 to capture the data from the given pins on the previous vector. Note that is does not actually generate a new vector.
Note also that any drive cycles on the target pins can also be captured, to avoid this the wavetable should be set up like this to infer a ‘D’ (Don’t Capture) on vectors where the target pin is being used to drive data:
PINS nvm_fail
0 d1:0 r1:D 0
1 d1:1 r1:D 1
2 r1:C Capt
3 r1:D NoCapt
Sometimes when generating vectors within a loop you may want to apply a capture retrospectively to a previous vector, passing in an offset option will allow you to do this.
Examples
$tester.cycle # This is the vector you want to capture
$tester.store :pin => pin(:fail) # This applys the required opcode to the given pins
$tester.cycle # This one gets captured
$tester.cycle
$tester.cycle
$tester.store(:pin => pin(:fail), :offset => -2) # Just realized I need to capture that earlier vector
# Capturing multiple pins:
$tester.cycle
$tester.store :pins => [pin(:fail), pin(:done)]
Since the V93K store operates on a pin level (rather than vector level as on the J750) equivalent functionality can also be achieved by setting the store attribute of the pin itself prior to calling $tester.cycle. However it is recommended to use the tester API to do the store if cross-compatiblity with other platforms, such as the J750, is required.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 59 def store(*pins) = pins.last.is_a?(Hash) ? pins.pop : {} = { offset: 0 }.merge() pins = pins.flatten.compact if pins.empty? fail 'For the V93K you must supply the pins to store/capture' end pins.each do |pin| pin.restore_state do pin.capture update_vector_pin_val pin, offset: [:offset] last_vector([:offset]).dont_compress = true last_vector([:offset]).contains_capture = true end end end |
#store_next_cycle(*pins) ⇒ Object
Capture the next vector generated to HRAM
This method applys a store vector (stv) opcode to the next vector to be generated, note that is does not actually generate a new vector.
On J750 the pins argument is ignored since the tester only supports whole vector capture.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 88 def store_next_cycle(*pins) = pins.last.is_a?(Hash) ? pins.pop : {} = { }.merge() pins = pins.flatten.compact if pins.empty? fail 'For the V93K you must supply the pins to store/capture' end pins.each { |pin| pin.save; pin.capture } # Register this clean up function to be run after the next vector # is generated, cool or what! preset_next_vector do |vector| vector.contains_capture = true pins.each(&:restore) end end |