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/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, Placeholder, Reg, RegCollection

Constant Summary

@@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:


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

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


86
87
88
# File 'lib/origen/registers.rb', line 86

def 
  @@bit_metadata ||= {}
end

.default_bit_meta_data(*args, &block) ⇒ Object

An alias for default_bit_metadata


118
119
120
# File 'lib/origen/registers.rb', line 118

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

.default_bit_metadataObject

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


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

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


102
103
104
# File 'lib/origen/registers.rb', line 102

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

.default_reg_metadataObject

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


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

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


79
80
81
# File 'lib/origen/registers.rb', line 79

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


127
128
129
# File 'lib/origen/registers.rb', line 127

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

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

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]
    aliases += meta[:aliases] if meta[:aliases]
    aliases.each { |_a| local_vars[attribute] = bit_info.delete(attribute) if bit_info.key?(attribute) }
  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 unless @max_address_reg_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


458
459
460
461
# File 'lib/origen/registers.rb', line 458

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


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

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 = temparray.push(@new_reg_attrs[name])
    else
      temparray = @new_reg_attrs[name]
    end
    temparray = 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
40
41
# File 'lib/origen/registers.rb', line 33

def bit_order
  @bit_order ||= begin
    if parent
      parent.bit_order
    else
      :lsb0
    end
  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)

280
281
282
# File 'lib/origen/registers.rb', line 280

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

#default_bit_metadataObject Also known as: default_bit_meta_data


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

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


422
423
424
425
426
427
428
429
430
# File 'lib/origen/registers.rb', line 422

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.


372
373
374
375
376
377
378
379
# File 'lib/origen/registers.rb', line 372

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


367
368
369
# File 'lib/origen/registers.rb', line 367

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

#delete_registersObject


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

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.


661
662
663
# File 'lib/origen/registers.rb', line 661

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)

486
487
488
489
490
491
492
493
494
495
496
# File 'lib/origen/registers.rb', line 486

def has_reg?(name, params = {})
  params = {
    test_for_true_false: true
  }.update(params)
  if params.key?(:enabled_features) || params.key?(:enabled_feature)
    return !!get_registers(params).include?(name)
  else
    params[:enabled_features] = :default
    return !!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.


445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/origen/registers.rb', line 445

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)

285
286
287
# File 'lib/origen/registers.rb', line 285

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


476
477
478
# File 'lib/origen/registers.rb', line 476

def max_address_reg_size
  @max_address_reg_size
end

#max_reg_addressObject

Returns the highest address of all registers that have been added


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

def max_reg_address
  @max_reg_address || 0
end

#min_reg_addressObject

Returns the lowest address of all registers that have been added


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

def min_reg_address
  @min_reg_address || 0
end

#read_register_missing!(reg) ⇒ Object


682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
# File 'lib/origen/registers.rb', line 682

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.


506
507
508
509
510
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
# File 'lib/origen/registers.rb', line 506

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)
        return _registers[name]
      elsif name =~ /\/(.+)\//
        regex = Regexp.last_match(1)
        return 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)
        return 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?
        return _registers
      else
        return 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


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

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

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

:nodoc:

Returns:

  • (Boolean)

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

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


665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
# File 'lib/origen/registers.rb', line 665

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