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/variables_file.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, VariablesFile
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
Same as the store method, except that the capture will be applied to the next vector to be generated.
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
428 429 430 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 428 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)
141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 141 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
369 370 371 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 369 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
117 118 119 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 117 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
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 380 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 header_comments = '' vec.comments.each do |comment| if comment.include? '#' comment = comment.gsub(/# /, '') comment = comment.gsub(/#/, '') if comment != '' header_comments << comment + "\cm" end end end if vec.pin_vals && ($_testers_enable_vector_comments || vector_comments) comment = "#{header_comments}#{vec.number}:#{vec.cycle} #{vec.inline_comment}" else inline = vec.inline_comment.empty? ? '' : " # #{vec.inline_comment}" comment = " #{header_comments}#{inline}" end if Origen.mode.simulation? || $_testers_no_inline_comments 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"
169 170 171 172 173 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 169 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
159 160 161 162 163 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 159 def handshake( = {}) = { }.merge() Pattern.split() end |
#local_subroutines ⇒ Object
Returns an array of subroutines created by the current pattern
374 375 376 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 374 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
317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 317 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)
194 195 196 197 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 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 194 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
364 365 366 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 364 def ( = {}) microcode 'SQPG STOP;' unless [:subroutine] end |
#pattern_header(options = {}) ⇒ Object
An internal method called by Origen to create the pattern header
333 334 335 336 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 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 333 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
289 290 291 292 293 294 295 296 297 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 289 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
422 423 424 425 426 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 422 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
110 111 112 113 114 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 110 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
Same as the store method, except that the capture will be applied to the next vector to be generated.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/origen_testers/smartest_based_tester/base.rb', line 84 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 |