Class: OrigenSim::Tester
- Inherits:
-
Object
- Object
- OrigenSim::Tester
- Includes:
- OrigenTesters::VectorBasedTester
- Defined in:
- lib/origen_sim/tester.rb
Overview
Responsible for interfacing the simulator with Origen
Constant Summary collapse
Instance Attribute Summary collapse
-
#out_of_bounds_handler ⇒ Object
Returns the value of attribute out_of_bounds_handler.
Instance Method Summary collapse
- #c1(msg, options = {}) ⇒ Object
- #capture ⇒ Object
- #cycle_count ⇒ Object
- #dut_version ⇒ Object
-
#flush(*args) ⇒ Object
Flush any buffered simulation output, this should cause live waveviewers to reflect the latest state and the console and log files to update.
-
#force(*args) ⇒ Object
Shorthand for simulator.force.
- #handshake(options = {}) ⇒ Object
-
#initialize(options = {}, &block) ⇒ Tester
constructor
A new instance of Tester.
- #log_file_written(path) ⇒ Object
- #loop_vectors(name, number_of_loops, options = {}) ⇒ Object (also: #loop_vector)
- #match(pin, state, timeout_in_cycles, options = {}) ⇒ Object
- #match_block(timeout_in_cycles, options = {}, &block) ⇒ Object
-
#peek(*args) ⇒ Object
Shorthand for simulator.peek.
-
#peek_real(*args) ⇒ Object
Shorthand for simulator.peek_real.
-
#poke(*args) ⇒ Object
Shorthand for simulator.poke.
-
#push_vector(options) ⇒ Object
This method intercepts vector data from Origen, removes white spaces and compresses repeats.
- #read_reg_cycles ⇒ Object
- #read_reg_meta_supplied=(val) ⇒ Object
- #read_reg_open? ⇒ Boolean
- #read_register(reg_or_val, options = {}) ⇒ Object
-
#release(*args) ⇒ Object
Shorthand for simulator.release.
- #set_timeset(name, period_in_ns) ⇒ Object
- #simulator ⇒ Object
- #ss(msg = nil) ⇒ Object
-
#start ⇒ Object
Start the simulator.
-
#store_next_cycle(*pins) ⇒ Object
Capture the next vector generated.
-
#sync_up ⇒ Object
Blocks the Origen process until the simulator indicates that it has processed all operations up to this point.
- #wait(*args) ⇒ Object
Constructor Details
#initialize(options = {}, &block) ⇒ Tester
Returns a new instance of Tester.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/origen_sim/tester.rb', line 10 def initialize( = {}, &block) # Use Origen's collector to allow options to be set either from the options hash, or from the block if block_given? opts = Origen::Utility.collector(hash: , merge_method: :keep_hash, &block).to_hash else opts = end simulator.configure(opts, &block) @comment_buffer = [] @last_comment_size = 0 @execution_time_in_ns = 0 super() end |
Instance Attribute Details
#out_of_bounds_handler ⇒ Object
Returns the value of attribute out_of_bounds_handler.
8 9 10 |
# File 'lib/origen_sim/tester.rb', line 8 def out_of_bounds_handler @out_of_bounds_handler end |
Instance Method Details
#c1(msg, options = {}) ⇒ Object
100 101 102 103 104 105 106 |
# File 'lib/origen_sim/tester.rb', line 100 def c1(msg, = {}) if @step_comment_on PatSeq.add_thread(msg) unless [:no_thread_id] simulator.log msg @comment_buffer << msg end end |
#capture ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/origen_sim/tester.rb', line 36 def capture simulator.sync do @sync_pins = [] @sync_cycles = 0 yield end @sync_pins.map do |pin| if @sync_cycles.size == 1 simulator.peek("#{simulator.testbench_top}.pins.#{pin.id}.sync_memory")[0] else simulator.peek("#{simulator.testbench_top}.pins.#{pin.id}.sync_memory").to_i[(@sync_cycles - 1)..0] end end end |
#cycle_count ⇒ Object
433 434 435 |
# File 'lib/origen_sim/tester.rb', line 433 def cycle_count simulator.simulation.cycle_count end |
#dut_version ⇒ Object
29 30 31 |
# File 'lib/origen_sim/tester.rb', line 29 def dut_version simulator.dut_version end |
#flush(*args) ⇒ Object
Flush any buffered simulation output, this should cause live waveviewers to reflect the latest state and the console and log files to update
64 65 66 |
# File 'lib/origen_sim/tester.rb', line 64 def flush(*args) simulator.flush(*args) end |
#force(*args) ⇒ Object
Shorthand for simulator.force
457 458 459 |
# File 'lib/origen_sim/tester.rb', line 457 def force(*args) simulator.force(*args) end |
#handshake(options = {}) ⇒ Object
33 34 |
# File 'lib/origen_sim/tester.rb', line 33 def handshake( = {}) end |
#log_file_written(path) ⇒ Object
243 244 245 |
# File 'lib/origen_sim/tester.rb', line 243 def log_file_written(path) simulator.simulation.log_files << path if simulator.simulation end |
#loop_vectors(name, number_of_loops, options = {}) ⇒ Object Also known as: loop_vector
114 115 116 117 118 |
# File 'lib/origen_sim/tester.rb', line 114 def loop_vectors(name, number_of_loops, = {}) number_of_loops.times do yield end end |
#match(pin, state, timeout_in_cycles, options = {}) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/origen_sim/tester.rb', line 161 def match(pin, state, timeout_in_cycles, = {}) if dut_version <= '0.12.0' OrigenSim.error "Use of match loops requires a DUT model compiled with OrigenSim version > 0.12.0, the current dut was compiled with #{dut_version}" end expected_val = state == :high ? 1 : 0 if [:pin2] expected_val2 = [:state2] == :high ? 1 : 0 end timed_out = true 10.times do (timeout_in_cycles / 10).cycles current_val = simulator.peek("dut.#{pin.rtl_name}").to_i if [:pin2] current_val2 = simulator.peek("dut.#{[:pin2].rtl_name}").to_i if current_val == expected_val || current_val2 == expected_val2 timed_out = false break end else if current_val == expected_val timed_out = false break end end end # Final assertion to make the pattern fail if the loop timed out if timed_out pin.restore_state do pin.assert!(expected_val) end if [:pin2] [:pin2].restore_state do [:pin2].assert!(expected_val2) end end end end |
#match_block(timeout_in_cycles, options = {}, &block) ⇒ Object
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 |
# File 'lib/origen_sim/tester.rb', line 199 def match_block(timeout_in_cycles, = {}, &block) if dut_version <= '0.12.0' OrigenSim.error "Use of match loops requires a DUT model compiled with OrigenSim version > 0.12.0, the current dut was compiled with #{dut_version}" end match_conditions = Origen::Utility::BlockArgs.new fail_conditions = Origen::Utility::BlockArgs.new if block.arity > 0 block.call(match_conditions, fail_conditions) else match_conditions.add(&block) end timed_out = true simulator.match_loop do 10.times do (timeout_in_cycles / 10).cycles # Consider the match resolved if any condition can execute without generating errors if match_conditions.any? do |condition| e = simulator.match_errors condition.call e == simulator.match_errors end timed_out = false break end end end # Final execution to make the pattern fail if the loop timed out if timed_out if fail_conditions.instance_variable_get(:@block_args).empty? match_conditions.each(&:call) else fail_conditions.each(&:call) end end end |
#peek(*args) ⇒ Object
Shorthand for simulator.peek
447 448 449 |
# File 'lib/origen_sim/tester.rb', line 447 def peek(*args) simulator.peek(*args) end |
#peek_real(*args) ⇒ Object
Shorthand for simulator.peek_real
452 453 454 |
# File 'lib/origen_sim/tester.rb', line 452 def peek_real(*args) simulator.peek_real(*args) end |
#poke(*args) ⇒ Object
Shorthand for simulator.poke
442 443 444 |
# File 'lib/origen_sim/tester.rb', line 442 def poke(*args) simulator.poke(*args) end |
#push_vector(options) ⇒ Object
This method intercepts vector data from Origen, removes white spaces and compresses repeats
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/origen_sim/tester.rb', line 79 def push_vector() if simulator.simulation.max_errors_exceeded fail Origen::Generator::AbortError, 'The max error count has been exceeded in the simulation' else unless [:timeset] puts 'No timeset defined!' puts 'Add one to your top level startup method or target like this:' puts 'tester.set_timeset("nvmbist", 40) # Where 40 is the period in ns' exit 1 end flush_comments unless @comment_buffer.empty? repeat = [:repeat] || 1 simulator.cycle(repeat) @execution_time_in_ns += repeat * tester.timeset.period_in_ns if @after_next_vector @after_next_vector.call(@after_next_vector_args) @after_next_vector = nil end end end |
#read_reg_cycles ⇒ Object
429 430 431 |
# File 'lib/origen_sim/tester.rb', line 429 def read_reg_cycles @read_reg_cycles end |
#read_reg_meta_supplied=(val) ⇒ Object
437 438 439 |
# File 'lib/origen_sim/tester.rb', line 437 def (val) @read_reg_meta_supplied = val end |
#read_reg_open? ⇒ Boolean
425 426 427 |
# File 'lib/origen_sim/tester.rb', line 425 def read_reg_open? @read_reg_open end |
#read_register(reg_or_val, options = {}) ⇒ Object
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 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 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 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 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 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
# File 'lib/origen_sim/tester.rb', line 247 def read_register(reg_or_val, = {}) # This could be called multiple times for the same transaction if read_reg_open? yield else @read_reg_meta_supplied = false @read_reg_open = true @read_reg_cycles = {} unless @supports_transactions_set @supports_transactions = dut_version > '0.15.0' @supports_transactions_set = true end if reg_or_val.respond_to?(:named_bits) bit_names = reg_or_val.named_bits.map { |name, bits| name }.uniq expected = bit_names.map do |name| bits = reg_or_val.bits(name) if bits.is_to_be_read? [name, bits.status_str(:read)] end end.compact # Save which bits are being read for later, the driver performing the read will # clear the register flags read_flags = reg_or_val.map(&:is_to_be_read?) end error_count = simulator.error_count simulator.start_read_reg_transaction if @supports_transactions yield if @supports_transactions errors_captured, exceeded_max_errors, errors = *(simulator.stop_read_reg_transaction) end @read_reg_open = false if simulator.error_count > error_count if @supports_transactions actual_data_available = true if exceeded_max_errors Origen.log.warning 'The number of errors in this transaction exceeded the capture buffer, the actual data reported here may not be accurate' end out_of_sync = simulator.simulation.cycle_count != simulator.cycle_count if out_of_sync Origen.log.warning 'Something has gone wrong and Origen and the simulator do not agree on the current cycle number, it is not possible to resolve the actual data' actual_data_available = false else diffs = [] errors.each do |error| if c = read_reg_cycles[error[:cycle]] if p = c[simulator.pins_by_rtl_name[error[:pin_name]]] if p[:position] diffs << [p[:position], error[:expected], error[:received]] end end end end if diffs.empty? if @read_reg_meta_supplied Origen.log.warning 'It looks like the miscompare(s) occurred on pins/cycles that are not associated with register data' non_data_miscompare = true else Origen.log.warning 'It looks like your current read register driver does not provide the necessary meta-data to map these errors to an actual register value' end actual_data_available = false end end else Origen.log.warning 'Your DUT needs to be compiled with a newer version of OrigenSim to support reporting of the actual read data from this failed transaction' actual_data_available = false end # If a register object has been supplied... if read_flags Origen.log.error "Errors occurred reading register #{reg_or_val.path}:" if actual_data_available actual = nil reg_or_val.preserve_flags do reg_or_val.each_with_index do |bit, i| bit.read if read_flags[i] end diffs.each do |position, expected, received| if position < reg_or_val.size if received == -1 || received == -2 reg_or_val[position].unknown = true else reg_or_val[position].write(received, force: true) end else # This bit position is beyond the bounds of the register if @out_of_bounds_handler @out_of_bounds_handler.call(position, received, expected, reg_or_val) else Origen.log.error "bit[#{position}] of read operation on #{reg_or_val.path}.#{reg_or_val.name}: expected #{expected} received #{received}" end end end actual = bit_names.map do |name| bits = reg_or_val.bits(name) if bits.is_to_be_read? [name, bits.status_str(:read)] end end.compact # Put the data back so the application behaves as it would if generating # for a non-simulation tester target diffs.each do |position, expected, received| reg_or_val[position].write(expected, force: true) if position < reg_or_val.size end end end expected.each do |name, expected| msg = "#{reg_or_val.path}.#{name}: expected #{expected}" if actual_data_available received_ = nil actual.each do |name2, received| if name == name2 received_ = received msg += " received #{received}" end end if expected == received_ Origen.log.info msg else Origen.log.error msg end else # This means that the correct data was read, but errors occurred on other pins/cycles during the transaction msg += " received #{expected}" if non_data_miscompare Origen.log.error msg end end else Origen.log.error 'Errors occurred while reading a register:' msg = "expected #{reg_or_val.to_s(16).upcase}" if actual_data_available actual = reg_or_val diffs.each do |position, expected, received| if received == -1 || received == -2 actual = '?' * reg_or_val.to_s(16).size break elsif received == 1 actual |= (1 << position) else lower = actual[(position - 1)..0] actual = actual >> (position + 1) actual = actual << (position + 1) actual |= lower end end if actual.is_a?(String) msg += " received #{actual}" else msg += " received #{actual.to_s(16).upcase}" end else # This means that the correct data was read, but errors occurred on other pins/cycles during the transaction msg += " received #{reg_or_val.to_s(16).upcase}" if non_data_miscompare end Origen.log.error msg end Origen.log.error caller.each do |line| if Pathname.new(line.split(':').first)..to_s =~ /^#{Origen.root}(?!(\/lbin|\/vendor\/gems)).*$/ Origen.log.error line end end end end end |
#release(*args) ⇒ Object
Shorthand for simulator.release
462 463 464 |
# File 'lib/origen_sim/tester.rb', line 462 def release(*args) simulator.release(*args) end |
#set_timeset(name, period_in_ns) ⇒ Object
68 69 70 71 72 73 74 75 76 |
# File 'lib/origen_sim/tester.rb', line 68 def set_timeset(name, period_in_ns) super # Need to remove this once OrigenTesters does it dut.timeset = name dut.current_timeset_period = period_in_ns # Now update the simulator with the new waves simulator.on_timeset_changed end |
#simulator ⇒ Object
25 26 27 |
# File 'lib/origen_sim/tester.rb', line 25 def simulator OrigenSim.simulator end |
#ss(msg = nil) ⇒ Object
108 109 110 111 112 |
# File 'lib/origen_sim/tester.rb', line 108 def ss(msg = nil) simulator.log '=' * 70 super simulator.log '=' * 70 end |
#start ⇒ Object
Start the simulator
52 53 54 |
# File 'lib/origen_sim/tester.rb', line 52 def start simulator.start end |
#store_next_cycle(*pins) ⇒ Object
Capture the next vector generated
This method applies a store request to the next vector to be generated, note that is does not actually generate a new vector.
The captured data is added to the captured_data array.
This method is intended to be used by pin drivers, see the #capture method for the application level API.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/origen_sim/tester.rb', line 134 def store_next_cycle(*pins) = pins.last.is_a?(Hash) ? pins.pop : {} if pins.empty? pins = dut.rtl_pins.values else pins_orig = pins.dup pins_orig.each do |p| if p.is_a? Origen::Pins::PinCollection pins.concat(p.map(&:id).map { |p| dut.pin(p) }) pins.delete(p) end end end if simulator.sync_active? && @sync_cycles @sync_cycles += 1 pins.each do |pin| @sync_pins << pin unless @sync_pins.include?(pin) end end pins.each(&:capture) # A store request is only valid for one cycle, this tells the simulator # to stop after the next vector is generated after_next_vector do pins.each { |pin| simulator.put("h^#{pin.simulation_index}") } end end |
#sync_up ⇒ Object
Blocks the Origen process until the simulator indicates that it has processed all operations up to this point
58 59 60 |
# File 'lib/origen_sim/tester.rb', line 58 def sync_up simulator.sync_up end |
#wait(*args) ⇒ Object
235 236 237 238 239 240 241 |
# File 'lib/origen_sim/tester.rb', line 235 def wait(*args) super if Origen.running_interactively? || (defined?(Byebug) && Byebug.try(:mode) == :attached) flush quiet: true end end |