Class: Origen::Tester::V93K
- Inherits:
-
Object
- Object
- Origen::Tester::V93K
- Includes:
- Origen::Tester
- Defined in:
- lib/origen/tester/v93k/v93k.rb,
lib/origen/tester/v93k/generator.rb,
lib/origen/tester/v93k/generator/flow.rb,
lib/origen/tester/v93k/generator/pattern.rb,
lib/origen/tester/v93k/generator/flow_node.rb,
lib/origen/tester/v93k/generator/test_suite.rb,
lib/origen/tester/v93k/generator/test_suites.rb,
lib/origen/tester/v93k/generator/test_method.rb,
lib/origen/tester/v93k/generator/test_methods.rb,
lib/origen/tester/v93k/generator/test_function.rb,
lib/origen/tester/v93k/generator/pattern_master.rb,
lib/origen/tester/v93k/generator/test_functions.rb,
lib/origen/tester/v93k/generator/flow_node/print.rb
Overview
Tester model to generate .avc patterns for the Verigy 930000
Basic Usage
$tester = Origen::Tester::V93K.new
$tester.cycle # Generate a vector
Many more methods exist to generate V93K specific micro-code, see below for details.
Also note that this class includes the base Tester module and so all methods described there are also available.
Defined Under Namespace
Modules: Generator
Instance Attribute Summary
Attributes included from API
#comment_level, #generating, #includes, #inhibit_comments, #inhibit_vectors
Instance Method Summary (collapse)
- - (Object) before_timeset_change(options = {})
-
- (Object) call_subroutine(name, options = {})
Call a subroutine.
-
- (Object) called_subroutines
Returns an array of subroutines called while generating the current pattern.
-
- (Object) end_subroutine(_cond = false)
Ends the current subroutine that was started with a previous call to start_subroutine.
-
- (Object) format_vector(vec)
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.
-
- (Object) freq_count(_pin, options = {})
Do a frequency measure.
-
- (Object) handshake(options = {})
Handshake with the tester.
-
- (V93K) initialize
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.
-
- (Object) local_subroutines
Returns an array of subroutines created by the current pattern.
-
- (Object) loop_vectors(name = nil, number_of_loops = 1, _global = false)
(also: #loop_vector)
Add a loop to the pattern.
-
- (Object) match(pin, state, timeout, options = {})
Generates a match loop on up to two pins.
-
- (Object) pattern_footer(_options = {})
An internal method called by Origen to generate the pattern footer.
-
- (Object) pattern_header(options = {})
An internal method called by Origen to create the pattern header.
-
- (Object) propagation_delay
Returns the number of cycles to wait for any fails to propagate through the pipeline based on the current timeset.
-
- (Object) repeat_previous
All vectors generated with the supplied block will have all pins set to the repeat previous state.
-
- (Object) start_subroutine(name)
Start a subroutine.
-
- (Object) store(*pins)
(also: #capture)
Capture the pin data from a vector to the tester.
-
- (Object) store_next_cycle(*pins)
Capture the next vector generated to HRAM.
- - (Boolean) v93k?
Methods included from Origen::Tester
Methods included from API
#annotate, #any_clocks_running?, #c1, #c2, #clocks_running, #comment_char, #cycle, #doc?, #generate?, #generating_pattern?, #generating_program?, #ignore_fails, #import_test_time, #inhibit_vectors_and_comments, #is_command_based?, #is_vector_based?, #j750?, #j750_hpt?, #name, #pat_extension, #pattern_section, #pins_need_toggling, #pop_running_clock, #program_comment_char, #push_running_clock, #slice_repeats, #snip, #ss, #step_comment_prefix, #ultraflex?, #update_running_clocks
Methods included from Timing
#called_timesets, #count, #current_period_in_ns, #current_timeset, #cycles_to_ms, #cycles_to_time, #cycles_to_ts, #cycles_to_us, #delay, #max_repeat_loop, #ms_to_cycles, #ns_to_cycles, #s_to_cycles, #set_timeset, #timeset_changed, #us_to_cycles, #wait
Methods included from VectorGenerator
#_render, #add_microcode_to_last_or_cycle, #before_write_pattern_line, #compressable_vector?, #current_pin_vals, #cycle_count, #dec_vec_count, #dont_compress, #dont_compress=, #expand_vector, #format, #format_pin_state, #get_pingroup, #inc_cycle_count, #inc_vec_count, #inhibit_pin, #inhibited_pins, #last_object, #last_vector, #multi_mode_optimize, #optimize, #ordered_pins, #ordered_pins_cache, #pingroup_map, #pipeline, #preset_next_vector, #push_comment, #push_microcode, #push_vector, #render, #render_body, #render_footer, #render_header, #render_template, #reset_cycle_count, #stage, #track_and_format_vector, #update_pin_from_formatted_state, #update_vector, #update_vector_pin_val, #vec_count, #vector_group_size, #vector_group_size=, #with_vector_group_size
Constructor Details
- (V93K) initialize
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
27 28 29 30 31 32 33 34 35 |
# File 'lib/origen/tester/v93k/v93k.rb', line 27 def initialize @max_repeat_loop = 65_535 @pat_extension = 'avc' @compress = true # @support_repeat_previous = true @match_entries = 10 @name = 'v93k' @comment_char = '#' end |
Instance Method Details
- (Object) before_timeset_change(options = {})
411 412 413 |
# File 'lib/origen/tester/v93k/v93k.rb', line 411 def before_timeset_change( = {}) microcode "SQPG CTIM #{[:new].name};" end |
- (Object) call_subroutine(name, options = {})
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)
159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/origen/tester/v93k/v93k.rb', line 159 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 |
- (Object) called_subroutines
Returns an array of subroutines called while generating the current pattern
366 367 368 |
# File 'lib/origen/tester/v93k/v93k.rb', line 366 def called_subroutines @called_subroutines ||= [] end |
- (Object) end_subroutine(_cond = false)
Ends the current subroutine that was started with a previous call to start_subroutine
135 136 137 |
# File 'lib/origen/tester/v93k/v93k.rb', line 135 def end_subroutine(_cond = false) Pattern.close call_shutdown_callbacks: false end |
- (Object) format_vector(vec)
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
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
# File 'lib/origen/tester/v93k/v93k.rb', line 377 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 && vec.number && vec.cycle_number # comment = " // Vector #{@pattern_vectors}, Cycle #{@pattern_cycles}" # else comment = '' # end "#{microcode.ljust(25)} #{timeset.ljust(25)} #{pin_vals} #{comment}" end |
- (Object) freq_count(_pin, options = {})
Do a frequency measure.
Examples
$tester.freq_count($top.pin(:d_out)) # Freq measure on pin "d_out"
187 188 189 190 191 |
# File 'lib/origen/tester/v93k/v93k.rb', line 187 def freq_count(_pin, = {}) = { }.merge() Pattern.split() end |
- (Object) handshake(options = {})
Handshake with the tester.
Examples
$tester.handshake # Pass control to the tester for a measurement
177 178 179 180 181 |
# File 'lib/origen/tester/v93k/v93k.rb', line 177 def handshake( = {}) = { }.merge() Pattern.split() end |
- (Object) local_subroutines
Returns an array of subroutines created by the current pattern
371 372 373 |
# File 'lib/origen/tester/v93k/v93k.rb', line 371 def local_subroutines # :nodoc: @local_subroutines ||= [] end |
- (Object) loop_vectors(name = nil, number_of_loops = 1, _global = false) 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
325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/origen/tester/v93k/v93k.rb', line 325 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 |
- (Object) match(pin, state, timeout, options = {})
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)
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 290 291 292 293 |
# File 'lib/origen/tester/v93k/v93k.rb', line 212 def match(pin, state, timeout, = {}) = { check_for_fails: false, pin2: false, state2: false, force_fail_on_timeout: true, 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}" number_of_loops = (timeout.to_f / 8).ceil microcode "SQPG MACT #{number_of_loops};" # Strobe the pin for the required state state == :low ? pin.expect_lo! : pin.expect_hi! pin.dont_care # Wait for 7 vectors before re-checking, this keeps the loop to 8 vectors which allows the test results # to be reconstructed cleanly if multiple loops are called in a pattern microcode 'SQPG MRPT 7;' # Not sure if no compression is really required here... 7.times do cycle(dont_compress: true) end microcode 'SQPG PADDING;' 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.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 microcode 'SQPG RSUB;' end end |
- (Object) pattern_footer(_options = {})
An internal method called by Origen to generate the pattern footer
361 362 363 |
# File 'lib/origen/tester/v93k/v93k.rb', line 361 def ( = {}) microcode 'SQPG STOP;' end |
- (Object) pattern_header(options = {})
An internal method called by Origen to create the pattern header
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
# File 'lib/origen/tester/v93k/v93k.rb', line 341 def pattern_header( = {}) = { }.merge() pin_list = ordered_pins.map do |p| if Origen.app.pin_pattern_order.include?(p.id) p.id # specified name overrides pin name else p.name end end.join(' ') microcode "FORMAT #{pin_list};" 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 |
- (Object) propagation_delay
Returns the number of cycles to wait for any fails to propagate through the pipeline based on the current timeset
297 298 299 300 301 302 303 304 305 |
# File 'lib/origen/tester/v93k/v93k.rb', line 297 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 |
- (Object) repeat_previous
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
405 406 407 408 409 |
# File 'lib/origen/tester/v93k/v93k.rb', line 405 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 |
- (Object) start_subroutine(name)
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
128 129 130 131 132 |
# File 'lib/origen/tester/v93k/v93k.rb', line 128 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 end |
- (Object) store(*pins) 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.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/origen/tester/v93k/v93k.rb', line 75 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 end end end |
- (Object) store_next_cycle(*pins)
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.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/origen/tester/v93k/v93k.rb', line 103 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 pins.each(&:restore) end end |
- (Boolean) v93k?
415 416 417 |
# File 'lib/origen/tester/v93k/v93k.rb', line 415 def v93k? true end |