Class: Origen::Registers::BitCollection

Inherits:
Array show all
Includes:
Netlist::Connectable, SubBlocks::Path
Defined in:
lib/origen/registers/bit_collection.rb

Overview

This is a regular Ruby array that is used to store collections of Bit objects, it has additional methods added to allow interaction with the contained bits. All Ruby array methods are also available - www.ruby-doc.org/core/classes/Array.html

A BitCollection is returned whenever a subset of bits is requested from a register. Also whenever any of these methods are called on a register object a BitCollection is created on the fly that contains all bits in the register. This means that when interacting with a Register, a single Bit, or a group of Bit objects, the same API can be used as described below.

Direct Known Subclasses

Ports::BitCollection

Constant Summary collapse

DONT_CARE_CHAR =
'X'
OVERLAY_CHAR =
'V'
STORE_CHAR =
'S'
UNKNOWN_CHAR =
'?'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Netlist::Connectable

#connect_to

Methods included from SubBlocks::Path

#abs_path=, #path, #path=

Methods inherited from Array

#dups, #dups?, #dups_with_index, #ids, #include_hash?, #include_hash_with_key?

Constructor Details

#initialize(reg, name, data = [], options = {}) ⇒ BitCollection

:nodoc:



23
24
25
26
27
28
29
30
31
# File 'lib/origen/registers/bit_collection.rb', line 23

def initialize(reg, name, data = [], options = {}) # :nodoc:
  if reg.respond_to?(:has_bits_enabled_by_feature?) && reg.has_parameter_bound_bits?
    reg.update_bound_bits unless reg.updating_bound_bits?
  end
  @reg = reg
  @name = name
  @with_bit_order = options[:with_bit_order] || :lsb0
  [data].flatten.each { |item| self << item }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

All other methods send to bit 0



731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
# File 'lib/origen/registers/bit_collection.rb', line 731

def method_missing(method, *args, &block) # :nodoc:
  if first.respond_to?(method)
    if size > 1
      if [:meta, :meta_data, :metadata].include?(method.to_sym) ||
         first.(method)
        first.send(method, *args, &block)
      else
        fail "Error, calling #{method} on a multi-bit collection is not implemented!"
      end
    else
      first.send(method, *args, &block)
    end
  else
    fail "BitCollection does not have a method named #{method}!"
  end
end

Instance Attribute Details

#nameObject Also known as: id

Returns the value of attribute name.



20
21
22
# File 'lib/origen/registers/bit_collection.rb', line 20

def name
  @name
end

Class Method Details

.dummy(reg, name = nil, options = {}) ⇒ Object

Returns a dummy bit collection that is populated with un-writable bits that will read back as 0. This can be useful for padding out spaces in registers with something that responds like conventional bits.



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/origen/registers/bit_collection.rb', line 302

def self.dummy(reg, name = nil, options = {})
  name, options = nil, name if name.is_a?(Hash)
  options = {
    size: 8,
    pos:  0
  }.merge(options)
  collection = new(reg, name)
  pos = options[:pos]
  options[:size].times do
    bit = Bit.new(reg, pos, writable: false, feature: :dummy_feature)
    collection << bit
    pos += 1
  end
  collection
end

Instance Method Details

#[](*indexes) ⇒ Object Also known as: bits, bit

Access bits by index

*Note* This method behaves differently depending on the setting of @with_bit_order

If @with_bit_order == :lsb0 (default) index 0 refers to the lsb of the bit collection If @with_bit_order == :msb0 index 0 refers to the msb of the bit collection

Example

dut.reg(:some_reg).bits(:some_field).with_msb0[0..1] # returns 2 most significant bits
dut.reg(:some_reg).bits(:some_field)[0..1]           # returns 2 least significant bits

*Note* Internal methods should call this method using a with_lsb0 block around the code or alternatively use the shift_out methods

Example

with_lsb0 do
  saved_bit = [index]
  [index] = some_new_bit_or_operation
end


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/origen/registers/bit_collection.rb', line 89

def [](*indexes)
  return self if indexes.empty?

  b = BitCollection.new(parent, name)
  expand_and_order(*indexes).each do |i|
    b << fetch(i)
  end
  # When 1 bit requested just return that bit, this is consistent with the original
  # behaviour before sub collections were added
  if b.size == 1
    b.first
  else
    # maintain downstream bit numbering setting
    @with_bit_order == :msb0 ? b.with_msb0 : b
  end
end

#abs_pathObject



130
131
132
# File 'lib/origen/registers/bit_collection.rb', line 130

def abs_path
  first.abs_path
end

#access(value = nil) ⇒ Object

Returns the access attribute of the first contained bit, in most normal use cases the application will naturally guarantee that when this is called all of the bits in the collection have the same access value.

If you are worried about hitting the case where some bits have different values then use access!, but this will be a bit less efficient



249
250
251
252
253
254
255
256
# File 'lib/origen/registers/bit_collection.rb', line 249

def access(value = nil)
  if value.nil?
    first.access
  else # set access
    each { |b| b.set_access(value) }
    self
  end
end

#access!Object

Like access but will raise an error if not all bits in the collection have the same access value



260
261
262
263
264
265
266
267
# File 'lib/origen/registers/bit_collection.rb', line 260

def access!
  val = access
  if any? { |b| b.access != val }
    fail 'Not all bits the collection have the same access value!'
  end

  val
end

#add_name(name) ⇒ Object

:nodoc:



717
718
719
720
721
722
723
724
# File 'lib/origen/registers/bit_collection.rb', line 717

def add_name(name) # :nodoc:
  if @name == :unknown
    @name = name
  elsif ![name].flatten.include?(name)
    @name = [@name, name].flatten
  end
  self
end

#append_overlays(value) ⇒ Object

Append a value, for example a block identifier, to all overlays

Example

reg(:data).overlay("data_val")
reg(:data).append_overlays("_0")
reg(:data).overlay_str           # => "data_val_0"


704
705
706
707
708
709
# File 'lib/origen/registers/bit_collection.rb', line 704

def append_overlays(value)
  each do |bit|
    bit.overlay(bit.overlay_str + value) if bit.has_overlay?
  end
  self
end

#bind(live_parameter) ⇒ Object



67
68
69
# File 'lib/origen/registers/bit_collection.rb', line 67

def bind(live_parameter)
  parent.bind(name, live_parameter)
end

#bit_orderObject

Returns the bit order of the parent register



34
35
36
# File 'lib/origen/registers/bit_collection.rb', line 34

def bit_order
  parent.bit_order
end

#bit_value_descriptions(_bitname = nil) ⇒ Object



290
291
292
293
294
295
296
297
# File 'lib/origen/registers/bit_collection.rb', line 290

def bit_value_descriptions(_bitname = nil)
  options = _bitname.is_a?(Hash) ? _bitname : {}
  if name == :unknown
    []
  else
    @reg.bit_value_descriptions(name, options)
  end
end

#clear_flagsObject

Calls the clear_flags method on all bits, see Bit#clear_flags for more details



528
529
530
531
# File 'lib/origen/registers/bit_collection.rb', line 528

def clear_flags
  each(&:clear_flags)
  self
end

#clear_startObject

Clear any start set bits back to 0



876
877
878
879
# File 'lib/origen/registers/bit_collection.rb', line 876

def clear_start
  each(&:clear_start)
  self
end

#clear_w1cObject

Clear any w1c set bits back to 0



870
871
872
873
# File 'lib/origen/registers/bit_collection.rb', line 870

def clear_w1c
  each(&:clear_w1c)
  self
end

#clr_only(value) ⇒ Object

Modify clr_only for bits in collection



851
852
853
854
# File 'lib/origen/registers/bit_collection.rb', line 851

def clr_only(value)
  shift_out_with_index { |bit, i| bit.clr_only = (value[i] == 0b1) }
  self
end

#contains_bits?Boolean

Returns:

  • (Boolean)


318
319
320
# File 'lib/origen/registers/bit_collection.rb', line 318

def contains_bits?
  true
end

#copy_all(reg) ⇒ Object

Copies all data and flags from one bit collection (or reg) object to another

This method will accept a dumb value as the argument, in which case it is essentially a write, however it will also clear all flags.



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
# File 'lib/origen/registers/bit_collection.rb', line 215

def copy_all(reg)
  if reg.respond_to?(:contains_bits?) && reg.contains_bits?
    unless reg.size == size
      puts 'Bit collection copy must be performed on collections of the same size.'
      puts 'You can fix this by calling copy on a subset of the bits you require, e.g.'
      puts '  larger_bit_collection[3..0].copy_all(smaller_bit_collection)'
      puts
      fail 'Mismatched size for bit collection copy'
    end
    # safely handle collections with differing with_bit_order settings
    with_lsb0 do
      reg.shift_out_with_index do |source_bit, i|
        if source_bit
          self[i].overlay(source_bit.overlay_str) if source_bit.has_overlay?
          self[i].write(source_bit.data)

          self[i].read if source_bit.is_to_be_read?
          self[i].store if source_bit.is_to_be_stored?
        end
      end
    end # of with_lsb0
  else
    write(reg)
    clear_flags
  end
  self
end

#dataObject Also known as: val, value

Returns the data value held by the collection

Example

reg(:control).write(0x55)
reg(:control).data         #  => 0x55, assuming the reg has the required bits to store that


335
336
337
338
339
340
341
342
343
# File 'lib/origen/registers/bit_collection.rb', line 335

def data
  data = 0
  shift_out_with_index do |bit, i|
    return undefined if bit.is_a?(Origen::UndefinedClass)

    data |= bit.data << i
  end
  data
end

#data_bObject

Returns the inverse of the data value held by the collection



348
349
350
351
# File 'lib/origen/registers/bit_collection.rb', line 348

def data_b
  # (& operation takes care of Bignum formatting issues)
  ~data & ((1 << size) - 1)
end

#data_reverseObject Also known as: reverse_data

Returns the reverse of the data value held by the collection



354
355
356
357
358
359
360
361
362
# File 'lib/origen/registers/bit_collection.rb', line 354

def data_reverse
  data = 0
  reverse_shift_out_with_index do |bit, i|
    return undefined if bit.is_a?(Origen::UndefinedClass)

    data |= bit.data << i
  end
  data
end

#deleteObject

Delete the contained bits from the parent Register



712
713
714
715
# File 'lib/origen/registers/bit_collection.rb', line 712

def delete
  @reg.delete_bits(self)
  self
end

#description(bitname = nil, options = {}) ⇒ Object

Returns the description of the given bit(s) if any, if none then an empty array will be returned

*Note* Adding a description field will override any comment-driven documentation of a bit collection (ie markdown style comments)



274
275
276
277
278
279
280
281
# File 'lib/origen/registers/bit_collection.rb', line 274

def description(bitname = nil, options = {})
  bitname, options = nil, bitname if bitname.is_a?(Hash)
  if name == :unknown
    []
  else
    @reg.description(name, options)
  end
end

#enable_mask(operation) ⇒ Object

Returns a value representing the bit collection / register where a bit value of 1 means the bit is enabled for the given operation.



429
430
431
432
433
434
435
436
437
438
439
440
441
# File 'lib/origen/registers/bit_collection.rb', line 429

def enable_mask(operation)
  str = ''
  shift_out_left do |bit|
    if operation == :store && bit.is_to_be_stored? ||
       operation == :read && bit.is_to_be_read? ||
       operation == :overlay && bit.has_overlay?
      str += '1'
    else
      str += '0'
    end
  end
  str.to_i(2)
end

#enabled?Boolean

Returns:

  • (Boolean)


834
835
836
# File 'lib/origen/registers/bit_collection.rb', line 834

def enabled?
  all?(&:enabled?)
end

#featureObject Also known as: features



802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
# File 'lib/origen/registers/bit_collection.rb', line 802

def feature
  feature = []
  feature << fetch(0).feature
  each { |bit| feature << bit.feature if bit.has_feature_constraint? }
  feature = feature.flatten.uniq unless feature.empty?
  feature.delete(nil) if feature.include?(nil)
  if !feature.empty?
    if feature.size == 1
      feature[0]
    else
      feature.uniq
    end
  else
    if Origen.config.strict_errors
      fail 'No feature found'
    end

    nil
  end
end

#full_name(bitname = nil, options = {}) ⇒ Object



283
284
285
286
287
288
# File 'lib/origen/registers/bit_collection.rb', line 283

def full_name(bitname = nil, options = {})
  bitname, options = nil, bitname if bitname.is_a?(Hash)
  unless name == :unknown
    @reg.full_name(name, options)
  end
end

#has_feature_constraint?(name = nil) ⇒ Boolean Also known as: enabled_by_feature?

Return true if there is any feature associated with these bits

Returns:

  • (Boolean)


825
826
827
828
829
830
831
# File 'lib/origen/registers/bit_collection.rb', line 825

def has_feature_constraint?(name = nil)
  if !name
    any?(&:has_feature_constraint?)
  else
    any? { |bit| bit.enabled_by_feature?(name) }
  end
end

#has_known_value?Boolean

Returns true if the values of all bits in the collection are known. The value will be unknown in cases where the reset value is undefined or determined by a memory location and where the register has not been written or read to a specific value yet.

Returns:

  • (Boolean)


757
758
759
# File 'lib/origen/registers/bit_collection.rb', line 757

def has_known_value?
  all?(&:has_known_value?)
end

#has_overlay?(name = nil) ⇒ Boolean

Returns true if any bits within are tagged for overlay, supply a specific name to require a specific overlay only

Example

myreg.overlay("data")
myreg.has_overlay?              # => true
myreg.has_overlay?("address")   # => false
myreg.has_overlay?("data")      # => true

Returns:

  • (Boolean)


550
551
552
# File 'lib/origen/registers/bit_collection.rb', line 550

def has_overlay?(name = nil)
  any? { |bit| bit.has_overlay?(name) }
end

#inspectObject



322
323
324
# File 'lib/origen/registers/bit_collection.rb', line 322

def inspect
  "<#{self.class}:#{object_id}>"
end

#is_readable?Boolean Also known as: readable?

Returns true if any bits in the collection are readable

Returns:

  • (Boolean)


845
846
847
# File 'lib/origen/registers/bit_collection.rb', line 845

def is_readable?
  any?(&:readable?)
end

#is_to_be_read?Boolean

Returns true if any bits have the read flag set - see Bit#is_to_be_read? for more details.

Returns:

  • (Boolean)


511
512
513
# File 'lib/origen/registers/bit_collection.rb', line 511

def is_to_be_read?
  any?(&:is_to_be_read?)
end

#is_to_be_stored?Boolean

Returns true if any bits have the store flag set - see Bit#is_to_be_stored? for more details.

Returns:

  • (Boolean)


517
518
519
# File 'lib/origen/registers/bit_collection.rb', line 517

def is_to_be_stored?
  any?(&:is_to_be_stored?)
end

#is_writable?Boolean Also known as: writable?

Returns true if any bits in the collection are writable

Returns:

  • (Boolean)


839
840
841
# File 'lib/origen/registers/bit_collection.rb', line 839

def is_writable?
  any?(&:writable?)
end

#nvm_depObject

Return nvm_dep value held by collection



863
864
865
866
867
# File 'lib/origen/registers/bit_collection.rb', line 863

def nvm_dep
  nvm_dep = 0
  shift_out_with_index { |bit, i| nvm_dep |= bit.nvm_dep << i }
  nvm_dep
end

#overlay(value) ⇒ Object

Attaches the supplied overlay string to all bits

Example

reg(:data).overlay(“data_val”)



446
447
448
449
# File 'lib/origen/registers/bit_collection.rb', line 446

def overlay(value)
  each { |bit| bit.overlay(value) }
  self
end

#overlay_strObject

Cycles through all bits and returns the last overlay value found, it is assumed therefore that all bits have the same overlay value when calling this method

Example

myreg.overlay("data")

myreg.overlay_str   # => "data"


560
561
562
563
564
565
566
# File 'lib/origen/registers/bit_collection.rb', line 560

def overlay_str
  result = ''
  each do |bit|
    result = bit.overlay_str if bit.has_overlay?
  end
  result.to_s
end

#ownerObject



726
727
728
# File 'lib/origen/registers/bit_collection.rb', line 726

def owner
  first.owner
end

#parentObject



108
109
110
# File 'lib/origen/registers/bit_collection.rb', line 108

def parent
  @reg
end

#path_varObject



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/origen/registers/bit_collection.rb', line 112

def path_var
  if first.path_var
    if first.path_var =~ /^\./
      base = parent.path(relative_to: parent.parent)
      "#{base}#{first.path_var}"
    else
      first.path_var
    end
  else
    base = parent.path(relative_to: parent.parent)
    if size == 1
      "#{base}[#{position}]"
    else
      "#{base}[#{position + size - 1}:#{position}]"
    end
  end
end

#positionObject

Returns the LSB position of the collection



327
328
329
# File 'lib/origen/registers/bit_collection.rb', line 327

def position
  first.position
end

#preserve_flagsObject

At the end of the given block, the status flags of all bits will be restored to the state that they were upon entry to the block



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/origen/registers/bit_collection.rb', line 195

def preserve_flags
  orig = []
  each do |bit|
    orig << [bit.overlay_str, bit.is_to_be_read?, bit.is_to_be_stored?]
  end
  yield
  each do |bit|
    bit.clear_flags
    flags = orig.shift
    bit.overlay(flags[0])
    bit.read if flags[1]
    bit.store if flags[2]
  end
  self
end

#read(value = nil, options = {}) ⇒ Object Also known as: assert

Will tag all bits for read and if a data value is supplied it will update the expected data for when the read is performed.



407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/origen/registers/bit_collection.rb', line 407

def read(value = nil, options = {}) # :nodoc:
  # First properly assign the args if value is absent...
  if value.is_a?(Hash)
    options = value
    value = nil
  end
  if value
    value = Reg.clean_value(value)
    write(value, force: true)
  end
  if options[:mask]
    shift_out_with_index { |bit, i| bit.read if options[:mask][i] == 1 }
    shift_out_with_index { |bit, i| bit.clear_read_flag if options[:mask][i] == 0 }
  else
    each(&:read)
  end
  self
end

#read!(value = nil, options = {}) ⇒ Object Also known as: assert!

Similar to write! this method will perform the standard read method and then make a call to $top.read_register(self) with the expectation that this method will implement a read event in the pattern.

Example

reg(:data).read!         # Read register :data, expecting whatever value it currently holds
reg(:data).read!(0x5555) # Read register :data, expecting 0x5555


588
589
590
591
592
593
594
595
596
# File 'lib/origen/registers/bit_collection.rb', line 588

def read!(value = nil, options = {})
  value, options = nil, value if value.is_a?(Hash)
  read(value, options) unless block_given?
  if block_given?
    yield size == @reg.size ? @reg : self
  end
  @reg.request(:read_register, options)
  self
end

#readable(value) ⇒ Object

Modify readable for bits in collection



797
798
799
800
# File 'lib/origen/registers/bit_collection.rb', line 797

def readable(value)
  shift_out_with_index { |bit, i| bit.readable = (value[i] == 0b1); bit.set_access_from_rw }
  self
end

#resetObject

Resets all bits, this clears all flags and assigns the data value back to the reset state



453
454
455
456
# File 'lib/origen/registers/bit_collection.rb', line 453

def reset
  each(&:reset)
  self
end

#reset_data(value = nil) ⇒ Object Also known as: reset_val, reset_value, reset_data=, reset_val=, reset_value=

Returns the reset value of the collection, note that this does not reset the register and the current data is maintained.

Example

reg(:control).write(0x55)
reg(:control).data         #  => 0x55
reg(:control).reset_data   #  => 0x11, assuming the reg was declared with a reset value of 0x11
reg(:control).data         #  => 0x55


769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
# File 'lib/origen/registers/bit_collection.rb', line 769

def reset_data(value = nil)
  # This method was originally setup to set the reset value by passing an argument
  if value
    shift_out_with_index { |bit, i| bit.reset_val = value[i] }
    self
  else
    data = 0
    shift_out_with_index do |bit, i|
      return bit.reset_data if bit.reset_data.is_a?(Symbol)

      data |= bit.reset_data << i
    end
    data
  end
end

#respond_to?(*args) ⇒ Boolean

Recognize that BitCollection responds to some Bit methods via method_missing

Returns:

  • (Boolean)


749
750
751
752
# File 'lib/origen/registers/bit_collection.rb', line 749

def respond_to?(*args) # :nodoc:
  sym = args.first
  first.respond_to?(sym) || super(sym)
end

#reverse_shift_out(&block) ⇒ Object

Yields each bit in the register, MSB first.



500
501
502
# File 'lib/origen/registers/bit_collection.rb', line 500

def reverse_shift_out(&block)
  reverse_each(&block)
end

#reverse_shift_out_with_index(&block) ⇒ Object

Yields each bit in the register and its index, MSB first.



505
506
507
# File 'lib/origen/registers/bit_collection.rb', line 505

def reverse_shift_out_with_index(&block)
  reverse_each.with_index(&block)
end

#set_only(value) ⇒ Object

Modify set_only for bits in collection



857
858
859
860
# File 'lib/origen/registers/bit_collection.rb', line 857

def set_only(value)
  shift_out_with_index { |bit, i| bit.set_only = (value[i] == 0b1) }
  self
end

#setting(value) ⇒ Object

Returns the value you would need to write to the register to put the given value in these bits



535
536
537
538
539
540
541
# File 'lib/origen/registers/bit_collection.rb', line 535

def setting(value)
  result = 0
  shift_out_with_index do |bit, i|
    result |= bit.setting(value[i])
  end
  result
end

#shift_left(data = 0) ⇒ Object

Shifts the data in the collection left by one place. The data held by the rightmost bit will be set to the given value (0 by default).

Examples:

myreg.data          # => 0b1111
myreg.shift_left
myreg.data          # => 0b1110
myreg.shift_left
myreg.data          # => 0b1100
myreg.shift_left(1)
myreg.data          # => 0b1001
myreg.shift_left(1)
myreg.data          # => 0b0011


961
962
963
964
965
966
967
968
969
# File 'lib/origen/registers/bit_collection.rb', line 961

def shift_left(data = 0)
  prev_bit = nil
  reverse_shift_out do |bit|
    prev_bit.write(bit.data) if prev_bit
    prev_bit = bit
  end
  prev_bit.write(data)
  self
end

#shift_out(&block) ⇒ Object

Yields each bit in the register, LSB first.



490
491
492
# File 'lib/origen/registers/bit_collection.rb', line 490

def shift_out(&block)
  each(&block)
end

#shift_out_leftObject

Shifts out a stream of bit objects corresponding to the size of the BitCollection. i.e. calling this on a 16-bit register this will pass back 16 bit objects. If there are holes in the given register then a dummy bit object will be returned that is not writable and which will always read as 0.

Example

reg(:data).shift_out_left do |bit|
    bist_shift(bit)
end


466
467
468
469
# File 'lib/origen/registers/bit_collection.rb', line 466

def shift_out_left
  # This is functionally equivalent to reverse_shift_out
  reverse_each { |bit| yield bit }
end

#shift_out_left_with_indexObject

Same as Reg#shift_out_left but includes the index counter



472
473
474
475
# File 'lib/origen/registers/bit_collection.rb', line 472

def shift_out_left_with_index
  # This is functionally equivalent to reverse_shift_out_with_index
  reverse_each.with_index { |bit, i| yield bit, i }
end

#shift_out_rightObject

Same as Reg#shift_out_left but starts from the LSB



478
479
480
481
# File 'lib/origen/registers/bit_collection.rb', line 478

def shift_out_right
  # This is functionally equivalent to shift_out, actually sends LSB first
  each { |bit| yield bit }
end

#shift_out_right_with_indexObject

Same as Reg#shift_out_right but includes the index counter



484
485
486
487
# File 'lib/origen/registers/bit_collection.rb', line 484

def shift_out_right_with_index
  # This is functionally equivalent to shift_out_with_index
  each_with_index { |bit, i| yield bit, i }
end

#shift_out_with_index(&block) ⇒ Object

Yields each bit in the register and its index, LSB first.



495
496
497
# File 'lib/origen/registers/bit_collection.rb', line 495

def shift_out_with_index(&block)
  each_with_index(&block)
end

#shift_right(data = 0) ⇒ Object

Shifts the data in the collection right by one place. The data held by the leftmost bit will be set to the given value (0 by default).

Examples:

myreg.data          # => 0b1111
myreg.shift_right
myreg.data          # => 0b0111
myreg.shift_right
myreg.data          # => 0b0011
myreg.shift_right(1)
myreg.data          # => 0b1001
myreg.shift_right(1)
myreg.data          # => 0b1100


984
985
986
987
988
989
990
991
992
# File 'lib/origen/registers/bit_collection.rb', line 984

def shift_right(data = 0)
  prev_bit = nil
  shift_out do |bit|
    prev_bit.write(bit.data) if prev_bit
    prev_bit = bit
  end
  prev_bit.write(data)
  self
end

#status_str(operation, options = {}) ⇒ Object

Provides a string summary of the bit collection / register state that would be applied to given operation (write or read). This is mainly intended to be useful when generating pattern comments describing an upcoming register transaction.

This highlights not only bit values bit the status of any flags or overlays that are currently set.

The data is presented in hex nibble format with individual nibbles are expanded to binary format whenever all 4 bits do not have the same status - e.g. if only one of the four is marked for read.

The following symbols are used to represent bit state:

X - Bit is don't care (not marked for read) V - Bit has been tagged with an overlay S - Bit is marked for store

Examples:


myreg.status_str(:write)   # => "0000"
myreg.status_str(:read)    # => "XXXX"
myreg[7..4].read(5)
myreg.status_str(:read)    # => "XX5X"
myreg[14].read(0)
myreg.status_str(:read)    # => "(x0xx)X5X"


907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
# File 'lib/origen/registers/bit_collection.rb', line 907

def status_str(operation, options = {})
  options = {
    mark_overlays: true
  }.merge(options)
  str = ''
  if operation == :read
    shift_out_left do |bit|
      if bit.is_to_be_stored?
        str += STORE_CHAR
      elsif bit.is_to_be_read?
        if bit.has_overlay? && options[:mark_overlays]
          str += OVERLAY_CHAR
        else
          if bit.has_known_value?
            str += bit.data.to_s
          else
            str += UNKNOWN_CHAR
          end
        end
      else
        str += DONT_CARE_CHAR
      end
    end
  elsif operation == :write
    shift_out_left do |bit|
      if bit.has_overlay? && options[:mark_overlays]
        str += OVERLAY_CHAR
      else
        if bit.has_known_value?
          str += bit.data.to_s
        else
          str += UNKNOWN_CHAR
        end
      end
    end
  else
    fail "Unknown operation (#{operation}), must be :read or :write"
  end
  make_hex_like(str, (size / 4.0).ceil)
end

#sticky_overlay(set = true) ⇒ Object Also known as: sticky_overlays

Normally whenever a register is processed by the $top.read_register method it will call Reg#clear_flags to acknowledge that the read has been performed, which clears the read and store flags for the given bits. Normally however you want overlays to stick around such that whenever a given bit is written/read its data is always picked from an overlay.
Call this passing in false for a given register to cause the overlay data to also be cleared by Reg#clear_flags.

Example

reg(:data).overlay("data_val")
reg(:data).has_overlay?           # => true
reg(:data).clear_flags
reg(:data).has_overlay?           # => true
reg(:data).sticky_overlay(false)
reg(:data).clear_flags
reg(:data).has_overlay?           # => false


614
615
616
617
# File 'lib/origen/registers/bit_collection.rb', line 614

def sticky_overlay(set = true)
  each { |bit| bit.sticky_overlay = set }
  self
end

#sticky_store(set = true) ⇒ Object

Similar to sticky_overlay this method affects how the store flags are treated by Reg#clear_flags.
The default is that store flags will get cleared by Reg#clear_flags, passing true into this method will override this and prevent them from clearing.

Example

reg(:data).sticky_store(true)
reg(:data).store
reg(:data).clear_flags         # Does not clear the request to store


628
629
630
631
# File 'lib/origen/registers/bit_collection.rb', line 628

def sticky_store(set = true)
  each { |bit| bit.sticky_store = set }
  self
end

#store(options = {}) ⇒ Object

Marks all bits to be stored



634
635
636
637
# File 'lib/origen/registers/bit_collection.rb', line 634

def store(options = {})
  each(&:store)
  self
end

#store!(options = {}) ⇒ Object

Marks all bits to be stored and then calls read!



640
641
642
643
644
# File 'lib/origen/registers/bit_collection.rb', line 640

def store!(options = {})
  store(options)
  read!(options)
  self
end

#store_overlay_bits(options = {}) ⇒ Object

Sets the store flag on all bits that already have the overlay flag set



656
657
658
659
660
661
662
663
# File 'lib/origen/registers/bit_collection.rb', line 656

def store_overlay_bits(options = {})
  # Pass in an array of any overlays that are to be excluded from store
  options = { exclude: [] }.merge(options)
  each do |bit|
    bit.store if bit.has_overlay? && !options[:exclude].include?(bit.overlay_str)
  end
  self
end

#store_overlay_bits!(options = {}) ⇒ Object

Sets the store flag on all bits that already have the overlay flag set and then calls $top.read_register passing self as the first argument



648
649
650
651
652
653
# File 'lib/origen/registers/bit_collection.rb', line 648

def store_overlay_bits!(options = {})
  store_overlay_bits(options)
  @reg.request(:read_register, options) # Bypass the normal read method since we don't want to
  # tag the other bits for read
  self
end

#sync(size = nil, options = {}) ⇒ Object Also known as: sync!

Update the register contents with the live value from the device under test.

The current tester needs to be an OrigenLink driver. Upon calling this method a request will be made to read the given register, the read data will be captured and the register model will be updated.

The register parent register object is returned, this means that calling .sync on a register or bitcollection object will automatically update it and the display the register in the console.

Normally this method should be called from a breakpoint during pattern debug, and it is not intended to be inserted into production pattern logic.



152
153
154
155
156
157
158
159
160
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
# File 'lib/origen/registers/bit_collection.rb', line 152

def sync(size = nil, options = {})
  size, options = nil, size if size.is_a?(Hash)
  if tester.respond_to?(:capture)
    preserve_flags do
      v = tester.capture do
        store!(sync: true)
      end
      if v.first
        # Serial shift
        if v.size == 1
          reverse_shift_out_with_index do |bit, i|
            bit.instance_variable_set('@updated_post_reset', true)
            bit.instance_variable_set('@data', v.first[i])
          end
        # Parallel shift
        else
          reverse_shift_out_with_index do |bit, i|
            bit.instance_variable_set('@updated_post_reset', true)
            bit.instance_variable_set('@data', v[i].to_i)
          end
        end
      else
        Origen.log.warning "No data was captured when attempting to sync register #{owner.name}, this is probably because the current read_register driver method does not implement store requests"
      end
    end
    if size
      puts "#{parent.address.to_s(16).upcase}: " + data.to_s(16).upcase.rjust(Origen.top_level.memory_width / 4, '0')
      if size > 1
        step = Origen.top_level.memory_width / 8
        Origen.top_level.mem(parent.address + step).sync(size - 1)
      end
      nil
    else
      parent
    end
  else
    Origen.log.warning 'Sync is not supported on the current tester driver, register not updated'
  end
end

#terminal?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/origen/registers/bit_collection.rb', line 63

def terminal?
  true
end

#unique_overlays {|current_overlay, length, data| ... } ⇒ Object

Will yield all unique overlay strings attached to the bits within the collection. It will also return the number of bits for the overlay (the length) and the current data value held in those bits.

Example

reg(:control).unique_overlays do |str, length, data|
    do_something(str, length, data)
end

Yields:

  • (current_overlay, length, data)


672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
# File 'lib/origen/registers/bit_collection.rb', line 672

def unique_overlays
  current_overlay = false
  length = 0
  data = 0
  shift_out_right do |bit|
    # Init the current overlay when the first one is encountered
    current_overlay = bit.overlay_str if bit.has_overlay? && !current_overlay

    if bit.has_overlay?
      if bit.overlay_str != current_overlay
        yield current_overlay, length, data if current_overlay
        length = 0
        data = 0
      end

      data = data | (bit.data << length)
      length += 1
    else
      yield current_overlay, length, data if current_overlay
      length = 0
      data = 0
      current_overlay = false
    end
  end
  yield current_overlay, length, data if current_overlay
end

#unknown=(val) ⇒ Object

Sets the unknown attribute on all contained bits



401
402
403
# File 'lib/origen/registers/bit_collection.rb', line 401

def unknown=(val)
  each { |bit| bit.unknown = val }
end

#update_required?Boolean

Returns true if any bits have the update_required flag set - see Bit#update_required? for more details.

Returns:

  • (Boolean)


523
524
525
# File 'lib/origen/registers/bit_collection.rb', line 523

def update_required?
  any?(&:update_required?)
end

#whole_reg?Boolean

Returns true if the collection contains all bits in the register

Returns:

  • (Boolean)


374
375
376
# File 'lib/origen/registers/bit_collection.rb', line 374

def whole_reg?
  size == parent.size
end

#with_bit_orderObject

Returns the bit numbering order to use when interpreting indeces



39
40
41
# File 'lib/origen/registers/bit_collection.rb', line 39

def with_bit_order
  @with_bit_order
end

#with_lsb0Object

Allow bit number interpreting to be explicitly set to lsb0



50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/origen/registers/bit_collection.rb', line 50

def with_lsb0
  if block_given?
    # run just the code block with lsb0 numbering (for internal methods)
    saved_wbo = @with_bit_order
    @with_bit_order = :lsb0
    yield
    @with_bit_order = saved_wbo
  else
    @with_bit_order = :lsb0
    self
  end
end

#with_msb0Object

Allow bit number interpreting to be explicitly set to msb0



44
45
46
47
# File 'lib/origen/registers/bit_collection.rb', line 44

def with_msb0
  @with_bit_order = :msb0
  self
end

#writable(value) ⇒ Object

Modify writable for bits in collection



791
792
793
794
# File 'lib/origen/registers/bit_collection.rb', line 791

def writable(value)
  shift_out_with_index { |bit, i| bit.writable = (value[i] == 0b1); bit.set_access_from_rw }
  self
end

#write(value, options = {}) ⇒ Object Also known as: data=, value=, val=

Set the data value of the collection within the patgen, but not on silicon - i.e. calling write will not trigger a pattern write event.



380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/origen/registers/bit_collection.rb', line 380

def write(value, options = {})
  # If an array is written it means a data value and an overlay have been supplied
  # in one go...
  if value.is_a?(Array) && !value.is_a?(BitCollection)
    overlay(value[1])
    value = value[0]
  end
  value = value.data if value.respond_to?('data')

  with_lsb0 do
    size.times do |i|
      self[i].write(value[i], options)
    end
  end
  self
end

#write!(value = nil, options = {}) ⇒ Object

Write the bit value on silicon. This method will update the data value of the bits and then call $top.write_register passing the owning register as the first argument. This method is expected to handle writing the current state of the register to silicon.



572
573
574
575
576
577
578
579
580
# File 'lib/origen/registers/bit_collection.rb', line 572

def write!(value = nil, options = {})
  value, options = nil, value if value.is_a?(Hash)
  write(value, options) if value
  if block_given?
    yield size == @reg.size ? @reg : self
  end
  @reg.request(:write_register, options)
  self
end