Module: Origen::Registers

Extended by:
ActiveSupport::Concern
Defined in:
lib/origen/registers.rb,
lib/origen/registers/bit.rb,
lib/origen/registers/reg.rb,
lib/origen/registers/domain.rb,
lib/origen/registers/container.rb,
lib/origen/registers/bit_collection.rb,
lib/origen/registers/msb0_delegator.rb,
lib/origen/registers/reg_collection.rb

Overview

Origen provides a powerful register class which you are encouraged to use when you wish to interact with a silicon register (or RAM location). By interacting with the register on silicon through the register API your pattern will automatically track silicon state, so you can set and forget bits in the patgen the same as you would do with a physical register. Include this module to add registers to your block, then use the macros described below to instantiate register objects

include Origen::Registers

Defined Under Namespace

Classes: Bit, BitCollection, Container, Domain, Msb0Delegator, Placeholder, Reg, RegCollection

Constant Summary collapse

@@reg_metadata =
{}
@@bit_metadata =
{}

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

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

:nodoc:



41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/origen/registers.rb', line 41

def method_missing(method, *args, &block) # :nodoc:
  orig_method = method
  if method[-1] == '!'
    bang = true
    method = method.to_s.chop.to_sym
  end
  if _registers.key?(method)
    r = reg(method)
    r.sync if bang
    r
  else
    super(orig_method, *args, &block)
  end
end

Class Method Details

.bit_metadataObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a lookup table containing all custom bit metadata defined by objects in an application



84
85
86
# File 'lib/origen/registers.rb', line 84

def 
  @@bit_metadata ||= {}
end

.default_bit_meta_data(*args, &block) ⇒ Object

An alias for default_bit_metadata



116
117
118
# File 'lib/origen/registers.rb', line 116

def (*args, &block)
  (*args, &block)
end

.default_bit_metadataObject

Can be called to add app specific meta data to all bits



105
106
107
108
109
110
111
112
113
# File 'lib/origen/registers.rb', line 105

def 
  Origen::Registers.[:global] ||= {}
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    Origen::Registers.[:global].merge!(collector.to_h)
  end
  Origen::Registers.[:global]
end

.default_reg_meta_data(*args, &block) ⇒ Object

An alias for default_reg_metadata



100
101
102
# File 'lib/origen/registers.rb', line 100

def (*args, &block)
  (*args, &block)
end

.default_reg_metadataObject

Can be called to add app specific meta data to all registers



89
90
91
92
93
94
95
96
97
# File 'lib/origen/registers.rb', line 89

def 
  Origen::Registers.[:global] ||= {}
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    Origen::Registers.[:global].merge!(collector.to_h)
  end
  Origen::Registers.[:global]
end

.reg_metadataObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a lookup table containing all custom register metadata defined by objects in an application



77
78
79
# File 'lib/origen/registers.rb', line 77

def 
  @@reg_metadata ||= {}
end

Instance Method Details

#_registersObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

All register objects are stored here, but they should be accessed via the _reg method to ensure that feature scoping is applied



125
126
127
# File 'lib/origen/registers.rb', line 125

def _registers
  @_registers ||= RegCollection.new(self)
end

#add_reg(id, address, size = nil, bit_info = {}, &_block) ⇒ Object

Add a register. When adding a register you must supply a name, an address, size in bits, and bit definitions, any bits that are not declared will be filled with dummy bit objects that are not writable and will read back as 0.

add_reg :control,  0x00,    16    :mode    => { :pos => 8, :bits => 8 },
                                  # Leaving out bits does 1 by default
                                  :launch  => { :pos => 6 },
                                  # The default reset state is 0, specify an alternative..
                                  :status  => { :pos => 4, :bits => 2, :res => 0b11 },
                                  :fail    => { :pos => 2 },
                                  :done    => { :pos => 0 }

Can be called on any object to add a register to it

Examples:

Name    Address  Size   Bit Definitions


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

def add_reg(id, address, size = nil, bit_info = {}, &_block)
  if address.is_a?(Hash)
    fail 'add_reg requires the address to be supplied as the 2nd argument, e.g. add_reg :my_reg, 0x1000'
  end

  size, bit_info = nil, size if size.is_a?(Hash)
  size ||= bit_info.delete(:size) || 32
  description = bit_info.delete(:description)

  local_vars = {}

  Reg::REG_LEVEL_ATTRIBUTES.each do |attribute, meta|
    aliases = [attribute[1..-1].to_sym]
    aliases += meta[:aliases] if meta[:aliases]
    aliases.each { |_a| local_vars[attribute] = bit_info.delete(_a) if bit_info.key?(_a) }
  end

  local_vars[:_reset] ||= :memory if local_vars[:_memory]
  @min_reg_address ||= address
  @max_reg_address ||= address
  # Must set an initial value, otherwise max_address_reg_size will be nil if a sub_block contains only
  # a single register.
  @max_address_reg_size ||= size
  @min_reg_address = address if address < @min_reg_address
  if address > @max_reg_address
    @max_address_reg_size = size
    @max_reg_address = address
  end
  @reg_define_file ||= define_file(caller[0])

  if block_given?
    @new_reg_attrs = { meta: bit_info }
    yield self
    bit_info = @new_reg_attrs
  else
    # If no block given then init with all writable bits unless bit_info has
    # been supplied
    unless bit_info.any? { |k, v| v.is_a?(Hash) && v[:pos] }
      bit_info = { d: { pos: 0, bits: size }.merge(bit_info) }
    end
  end
  if _registers[id] && Origen.config.strict_errors
    puts ''
    puts "Add register error, you have already added a register named #{id} to #{self.class}"
    puts ''
    fail 'Duplicate register error!'
  else
    attributes = {
      define_file: @reg_define_file,
      address:     address,
      size:        size,
      bit_info:    bit_info,
      description: description
    }
    Reg::REG_LEVEL_ATTRIBUTES.each do |attribute, _meta|
      attributes[attribute] = local_vars[attribute]
    end
    _registers[id] = Placeholder.new(self, id, attributes)
  end
  @reg_define_file = nil
end

#add_reg32(id, address, args = {}, &block) ⇒ Object



463
464
465
466
# File 'lib/origen/registers.rb', line 463

def add_reg32(id, address, args = {}, &block)
  @reg_define_file = define_file(caller[0])
  add_reg(id, address, 32, args, &block)
end

#bit(index, name, attrs = {}) ⇒ Object Also known as: bits

Called within an add_reg block to define bits



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

def bit(index, name, attrs = {})
  if index.is_a?(Range)
    msb = index.first
    lsb = index.last
    msb, lsb = lsb, msb if lsb > msb
    pos = lsb
    bits = (msb - lsb).abs + 1
  elsif index.is_a?(Numeric)
    pos = index
    bits = 1
  else
    fail 'No valid index supplied when defining a register bit!'
  end

  # Traynor, this could be more elegant
  # its just a dirty way to make the value of the
  # key in @new_reg_atts hash array (ie name) tie to
  # a value that is an array of hashes describing
  # data for each scrambled bit
  attrs = attrs.merge(pos: pos, bits: bits)
  temparray = []
  if @new_reg_attrs[name].nil?
    @new_reg_attrs[name] = attrs
  else
    if @new_reg_attrs[name].is_a? Hash
      temparray.push(@new_reg_attrs[name])
    else
      temparray = @new_reg_attrs[name]
    end
    temparray.push(attrs)
    # added the sort so that the order the registers bits is described is not important
    @new_reg_attrs[name] = temparray.sort { |a, b| b[:pos] <=> a[:pos] }

  end
end

#bit_orderObject

Returns the bit order attribute of the model (either :msb0 or :lsb0). If not explicitly defined on this model it will be inherited from the parent and will default to :lsb0 at the top-level



33
34
35
36
37
38
39
# File 'lib/origen/registers.rb', line 33

def bit_order
  @bit_order ||= if parent
                   parent.bit_order
                 else
                   :lsb0
                 end
end

#contains_bits?(obj) ⇒ Boolean

Returns true if the given object is one of the recognized Origen bit containers (bit collection, reg or container).

Returns:

  • (Boolean)


283
284
285
# File 'lib/origen/registers.rb', line 283

def contains_bits?(obj)
  obj.respond_to?(:contains_bits?) && obj.contains_bits?
end

#default_bit_metadataObject Also known as: default_bit_meta_data



437
438
439
440
441
442
443
444
445
# File 'lib/origen/registers.rb', line 437

def 
  Origen::Registers.[self.class] ||= {}
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    Origen::Registers.[self.class].merge!(collector.to_h)
  end
  Origen::Registers.[self.class]
end

#default_reg_metadataObject Also known as: default_reg_meta_data

Can be called to add app specific meta data that is isolated to all registers defined within a given class



426
427
428
429
430
431
432
433
434
# File 'lib/origen/registers.rb', line 426

def 
  Origen::Registers.[self.class] ||= {}
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    Origen::Registers.[self.class].merge!(collector.to_h)
  end
  Origen::Registers.[self.class]
end

#define_file(file) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



376
377
378
379
380
381
382
383
# File 'lib/origen/registers.rb', line 376

def define_file(file)
  if Origen.running_on_windows?
    fields = file.split(':')
    "#{fields[0]}:#{fields[1]}"
  else
    file.split(':').first
  end
end

#del_reg(id) ⇒ Object

Delete an existing register



371
372
373
# File 'lib/origen/registers.rb', line 371

def del_reg(id)
  _registers.delete(id)
end

#delete_registersObject



65
66
67
# File 'lib/origen/registers.rb', line 65

def delete_registers
  @_registers = nil
end

#dummy_reg(size = 16) ⇒ Object

Creates a dummy register. Equivalent to Reg.dummy except the reg owner is assigned as the caller rather than Reg. Use this if you need to call read! or write! on the dummy register object.



667
668
669
# File 'lib/origen/registers.rb', line 667

def dummy_reg(size = 16)
  Reg.new(self, 0, size, :dummy, init_as_writable: true)
end

#has_reg?(name, params = {}) ⇒ Boolean Also known as: has_reg

Returns true if the object contains a register matching the given name

Returns:

  • (Boolean)


491
492
493
494
495
496
497
498
499
500
501
# File 'lib/origen/registers.rb', line 491

def has_reg?(name, params = {})
  params = {
    test_for_true_false: true
  }.update(params)
  if params.key?(:enabled_features) || params.key?(:enabled_feature)
    !!get_registers(params).include?(name)
  else
    params[:enabled_features] = :default
    !!get_registers(params).include?(name)
  end
end

#instantiate_reg(id, attrs) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



449
450
451
452
453
454
455
456
457
458
459
460
461
# File 'lib/origen/registers.rb', line 449

def instantiate_reg(id, attrs)
  return _registers[id] unless _registers[id].is_a?(Origen::Registers::Placeholder)

  attributes = {
    define_file: attrs[:define_file],
    description: attrs[:description]
  }
  Reg::REG_LEVEL_ATTRIBUTES.each do |attribute, _meta|
    attributes[attribute] = attrs[attribute]
  end
  _registers[id] = Reg.new(self, attrs[:address], attrs[:size], id,
                           attrs[:bit_info].merge(attributes))
end

#is_a_bit?(obj) ⇒ Boolean

Returns true if the given object is an Origen bit

Returns:

  • (Boolean)


288
289
290
# File 'lib/origen/registers.rb', line 288

def is_a_bit?(obj)
  obj.is_a?(Origen::Registers::Bit)
end

#max_address_reg_sizeObject

Returns the size (in bits) of the register with the highest address, can be useful in combination with max_reg_address to work out the range of addresses containing registers



481
482
483
# File 'lib/origen/registers.rb', line 481

def max_address_reg_size
  @max_address_reg_size
end

#max_reg_addressObject

Returns the highest address of all registers that have been added



474
475
476
# File 'lib/origen/registers.rb', line 474

def max_reg_address
  @max_reg_address || 0
end

#min_reg_addressObject

Returns the lowest address of all registers that have been added



469
470
471
# File 'lib/origen/registers.rb', line 469

def min_reg_address
  @min_reg_address || 0
end

#read_register_missing!(reg) ⇒ Object



688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
# File 'lib/origen/registers.rb', line 688

def read_register_missing!(reg)
  klass = (try(:controller) || self).class
  puts ''
  puts ''
  puts <<-EOT
You have made a request to read register: #{reg.name}, however the #{klass}
class does not know how to do this yet. You should implement a read_register
method in the #{klass} like this:

  def read_register(reg, options={})
<logic to handle reading the reg object here>
  end
  EOT
  puts ''
  exit 1
end

#reg(*args, &block) ⇒ Object Also known as: regs

Returns

-the register object matching the given name
-or a hash of all registes matching a given regular expression
-or a hash of all registers, associated with a feature, if no name is specified.

Can also be used to define a new register if a block is supplied in which case it is equivalent to calling add_reg with a block.



511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
# File 'lib/origen/registers.rb', line 511

def reg(*args, &block)
  if block_given? || (args[1].is_a?(Integer) && !try(:_initialized?))
    @reg_define_file = define_file(caller[0])
    add_reg(*args, &block)
  else
    # Example use cases:
    # reg(:reg2)
    # reg(:name => :reg2)
    # reg('/reg2/')
    if !args.empty? && args.size == 1 && (args[0].class != Hash || (args[0].key?(:name) && args[0].size == 1))
      if args[0].class == Hash
        name = args[0][:name]
      else
        name = args.first
      end
      if has_reg(name)
        _registers[name]
      elsif name =~ /\/(.+)\//
        regex = Regexp.last_match(1)
        match_registers(regex)
      else
        if Origen.config.strict_errors
          puts ''
          if regs.empty?
            puts "#{self.class} does not have a register named #{name} or it is not enabled."
          else
            puts "#{self.class} does not have a register named #{name} or it is not enabled."
            puts 'You may need to add it. This could also be a typo, these are the valid register names:'
            puts regs.keys
          end
          puts ''
          fail 'Missing register error!'
        end
      end
    # Example use cases:
    # reg(:enabled_features => :all)
    # reg(:name => :reg2, enabled_features => :all)
    # reg(:name => :reg2, enabled_features => :fac)
    elsif !args.empty? && args.size == 1 && args[0].class == Hash
      params = args[0]

      # Example use case:
      # reg(:name => :reg2, :enabled_features => :all)
      if (params.key?(:enabled_features) || params.key?(:enabled_feature)) && params.key?(:name)
        name = params[:name]
        if has_reg(name, params)
          _registers[name]
        else
          reg_missing_error(params)
        end
      # Example use case:
      # reg(:enabled_features =>[:fac, fac2])
      elsif params.size == 1 && params.key?(:enabled_features)
        get_registers(enabled_features: params[:enabled_features])
      end

    # Example use case:
    # reg(:reg2, :enabled_features => :all)
    # reg(:reg2, :enabled_features => :default)
    # reg(:reg2, :enabled_features => :fac)
    elsif !args.empty? && args.size == 2
      name = args[0]
      params = args[1]
      name, params = params, name if name.class == Hash
      if has_reg(name, params)
        _registers[name]
      else
        reg_missing_error(params)
      end
    elsif args.empty?
      if _registers.empty?
        _registers
      else
        get_registers(enabled_features: :default)
      end
    else
      if Origen.config.strict_errors
        fail 'Invalid call to reg method or invalid arguments specified'
      end
    end
  end
end

#reset_registersObject

Resets all registers



486
487
488
# File 'lib/origen/registers.rb', line 486

def reset_registers
  regs.each { |_name, reg| reg.reset }
end

#respond_to?(sym, include_private = false) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


56
57
58
59
60
61
62
63
# File 'lib/origen/registers.rb', line 56

def respond_to?(sym, include_private = false) # :nodoc:
  if sym[-1] == '!'
    r = sym.to_s.chop.to_sym
    _registers.key?(r) || super(sym)
  else
    _registers.key?(sym) || super(sym)
  end
end

#write_register_missing!(reg) ⇒ Object



671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
# File 'lib/origen/registers.rb', line 671

def write_register_missing!(reg)
  klass = (try(:controller) || self).class
  puts ''
  puts ''
  puts <<-EOT
You have made a request to write register: #{reg.name}, however the #{klass}
class does not know how to do this yet. You should implement a write_register
method in the #{klass} like this:

  def write_register(reg, options={})
<logic to handle the writing of the reg object here>
  end
  EOT
  puts ''
  exit 1
end