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, Collector, Container, Domain, 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:



29
30
31
32
33
34
35
# File 'lib/origen/registers.rb', line 29

def method_missing(method, *args, &block) # :nodoc:
  if _registers.key?(method)
    reg(method)
  else
    super
  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



60
61
62
# File 'lib/origen/registers.rb', line 60

def 
  @@bit_metadata ||= {}
end

.default_bit_meta_data(*args, &block) ⇒ Object

An alias for default_bit_metadata



92
93
94
# File 'lib/origen/registers.rb', line 92

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

.default_bit_metadataObject

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



81
82
83
84
85
86
87
88
89
# File 'lib/origen/registers.rb', line 81

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

.default_reg_meta_data(*args, &block) ⇒ Object

An alias for default_reg_metadata



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

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

.default_reg_metadataObject

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



65
66
67
68
69
70
71
72
73
# File 'lib/origen/registers.rb', line 65

def 
  Origen::Registers.[:global] ||= {}
  if block_given?
    collector = Collector.new
    yield collector
    Origen::Registers.[:global].merge!(collector.store)
  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



53
54
55
# File 'lib/origen/registers.rb', line 53

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



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

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


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

def add_reg(id, address, size = nil, bit_info = {}, &_block)
  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
  @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
  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



428
429
430
431
# File 'lib/origen/registers.rb', line 428

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



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

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

#contains_bits?(obj) ⇒ Boolean

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



262
263
264
# File 'lib/origen/registers.rb', line 262

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

#default_bit_metadataObject Also known as: default_bit_meta_data



403
404
405
406
407
408
409
410
411
# File 'lib/origen/registers.rb', line 403

def 
  Origen::Registers.[self.class] ||= {}
  if block_given?
    collector = Collector.new
    yield collector
    Origen::Registers.[self.class].merge!(collector.store)
  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



392
393
394
395
396
397
398
399
400
# File 'lib/origen/registers.rb', line 392

def 
  Origen::Registers.[self.class] ||= {}
  if block_given?
    collector = Collector.new
    yield collector
    Origen::Registers.[self.class].merge!(collector.store)
  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.



342
343
344
345
346
347
348
349
# File 'lib/origen/registers.rb', line 342

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



337
338
339
# File 'lib/origen/registers.rb', line 337

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

#delete_registersObject



41
42
43
# File 'lib/origen/registers.rb', line 41

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.



616
617
618
# File 'lib/origen/registers.rb', line 616

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



456
457
458
459
460
461
462
463
464
465
466
# File 'lib/origen/registers.rb', line 456

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.



415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/origen/registers.rb', line 415

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



267
268
269
# File 'lib/origen/registers.rb', line 267

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



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

def max_address_reg_size
  @max_address_reg_size
end

#max_reg_addressObject

Returns the highest address of all registers that have been added



439
440
441
# File 'lib/origen/registers.rb', line 439

def max_reg_address
  @max_reg_address || 0
end

#min_reg_addressObject

Returns the lowest address of all registers that have been added



434
435
436
# File 'lib/origen/registers.rb', line 434

def min_reg_address
  @min_reg_address || 0
end

#read_register_missing!(reg) ⇒ Object



636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
# File 'lib/origen/registers.rb', line 636

def read_register_missing!(reg)
  puts ''
  puts ''
  puts <<-EOT
You have made a request to read register: #{reg.name}, however the #{self.class}
class does not know how to do this yet. You must implement a read_register
method in the #{self.class} 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 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.



474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
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
# File 'lib/origen/registers.rb', line 474

def reg(*args, &block)
  if block_given?
    @reg_define_file = define_file(caller[0])
    add_reg(*args, &block)
  else
    # Example use cases:
    # reg(:reg2)
    # reg(:name => :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]
      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



451
452
453
# File 'lib/origen/registers.rb', line 451

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

#respond_to?(sym) ⇒ Boolean

:nodoc:



37
38
39
# File 'lib/origen/registers.rb', line 37

def respond_to?(sym) # :nodoc:
  _registers.key?(sym) || super(sym)
end

#write_register_missing!(reg) ⇒ Object



620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
# File 'lib/origen/registers.rb', line 620

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

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