class Origen::Registers::Container
A container can be used to easily interface register operations to an IPS-style interface where the container will take care of data alignment and byte enable calculations. A container looks and behaves like a register and drivers should be able to accept a container in place of a regular register.
Here are some examples:
include Origen::Registers # Name Address Size Bits add_reg :r0, 4, 8, data => {:bits => 8} add_reg :r1, 5, 8, data => {:bits => 8} add_reg :r2, 6, 8, data => {:bits => 8} add_reg :r3, 7, 8, data => {:bits => 8} reg(:r0).write(0xB0) reg(:r1).write(0xB1) reg(:r2).write(0xB2) reg(:r3).write(0xB3) big = Container.new little = Container.new(:endian => :little) big.add(reg(:r0)).data # => 0x0000_00B0 little.add(reg(:r0)).data # => 0xB000_0000 big.byte_enable # => 0b0001 little.byte_enable # => 0b1000 big.empty big.data # => 0x0000_0000 big.address # => nil big.add(reg(:r2)) big.address # => 4 (longword aligned) big.add(reg(:r3)).add(reg(:r1) big.add.data # => 0xB3B2_B100 big.byte_enable # => 0b1110 # Treat it like it's a register in drivers: big.shift_out_left do |bit| pin(:tdi).drive!(bit.data) end # The address can be overridden big.empty big.add(reg(:r2), :address => 10) big.address # => 8 (longword aligned) # Containers can accomodate other containers big.empty lower_word = Container.new lower_word.add(:r0).add(:r1) big.add(:r3) lower_word.data # => 0x0000_B1B0 big.data # => 0xB300_0000 big.add(lower_word) big.data # => 0xB300_B1B0 lower_word.data # => 0x0000_B1B0 # Contained registers are the same register objects reg(:r0).write(0x55) big.data # => 0xB300_B155 lower_word.data # => 0x0000_B155
Attributes
The number of bits represented by an address increment of the contained registers. For example if the contained registers have a byte address this will return 8.
Set this to a string or an array of strings that represents the name of the object that owns the container. If present any owned_by
? requests made to the container will be evaluated against this string. If not then the request will be sent to the first contained register (if present).
Returns the currently held registers
Returns the currently held registers
The size of the container in bits
Public Class Methods
@param [Hash] options Options to customize the container @option options [Integer] :size (32) The size of the container in bits @option options [Symbol] :endian (:big) The endianness of the container, :big or :little
For example big endian means that 4 a 32-bit container the bytes are arranged [3,2,1,0] whereas a little endian container would be [0,1,2,3].
@option options [Integer] :bits_per_address (8) The number of bits that will be represented
by an address increment of the given register's addresses
# File lib/origen/registers/container.rb, line 89 def initialize(options = {}) options = { size: 32, endian: :big, bits_per_address: 8 }.merge(options) @size = options[:size] @endian = options[:endian] @owned_by = options[:owned_by] @bits_per_address = options[:bits_per_address] @regs = [] @addresses = {} end
Public Instance Methods
Returns the bit at the given bit position if it exists, otherwise returns an un-writable bit
# File lib/origen/registers/container.rb, line 273 def [](i) bit_at_position(i) end
Add the given register to the container, currently there is no error checking performed to ensure that it doesn’t overlap with any existing contained registers.
# File lib/origen/registers/container.rb, line 110 def add(reg, options = {}) @regs << reg addr = options[:address] || options[:addr] @addresses[reg] = addr if addr @regs.sort_by! { |reg| address_of_reg(reg) } self end
Returns the aligned address of the container based on the address of the currently contained registers
# File lib/origen/registers/container.rb, line 173 def address unless @regs.empty? addr = address_of_reg(@regs.first) shift = Math.log(size / bits_per_address, 2) (addr >> shift) << shift end end
@api private
# File lib/origen/registers/container.rb, line 119 def address_of_reg(reg) @addresses[reg] || reg.address end
# File lib/origen/registers/container.rb, line 211 def big_endian? @endian == :big end
Returns the bit at the given bit position if it exists, otherwise returns an un-writable bit
# File lib/origen/registers/container.rb, line 255 def bit_at_position(i) reg = regs.find { |reg| reg_contains_position?(reg, i) } if reg reg[i - bit_shift_for_reg(reg)] else dummy_bit end end
@api private
# File lib/origen/registers/container.rb, line 207 def bit_shift_for_reg(reg) shift_for_reg(reg) * bits_per_address end
Returns the byte enable required to update the contained registers.
# File lib/origen/registers/container.rb, line 183 def byte_enable enable = 0 regs.each do |reg| enable_bits = 0.ones_comp(reg.size / bits_per_address) enable += (enable_bits << shift_for_reg(reg)) end enable end
Call the clear_flags
on all contained registers
# File lib/origen/registers/container.rb, line 283 def clear_flags @regs.each(&:clear_flags) end
# File lib/origen/registers/container.rb, line 103 def contains_bits? true end
Returns the data held by the contained registers where the data from each register is shifted into the correct position
# File lib/origen/registers/container.rb, line 125 def data d = 0 regs.each do |reg| d += (reg.data << bit_shift_for_reg(reg)) end d end
Data bar, the ones complement of the current data value of the container
# File lib/origen/registers/container.rb, line 137 def data_b ~data & ((1 << size) - 1) end
@api private
# File lib/origen/registers/container.rb, line 278 def dummy_bit @dummy_bit ||= Bit.new(self, 0, writable: false) end
Remove all registers from the container
# File lib/origen/registers/container.rb, line 142 def empty @regs = [] @addresses = {} self end
# File lib/origen/registers/container.rb, line 215 def little_endian? !big_endian? end
@api private
# File lib/origen/registers/container.rb, line 193 def local_addr_for_reg(reg) address_of_reg(reg) & 0.ones_comp(Math.log(size / bits_per_address, 2)) end
Proxies to the Reg#owned_by?
method
# File lib/origen/registers/container.rb, line 157 def owned_by?(name) if owned_by [owned_by].flatten.any? do |al| al.to_s =~ /#{name}/i end else if @regs.empty? false else @regs.first.owned_by?(name) end end end
Returns the owner of the contained registers (assumed to be the same for all)
# File lib/origen/registers/container.rb, line 150 def owner unless @regs.empty? @regs.first.owner end end
@api private
# File lib/origen/registers/container.rb, line 265 def reg_contains_position?(reg, position) start = bit_shift_for_reg(reg) stop = start + reg.size - 1 position >= start && position <= stop end
@api private
# File lib/origen/registers/container.rb, line 198 def shift_for_reg(reg) if big_endian? local_addr_for_reg(reg) else (size / bits_per_address) - (local_addr_for_reg(reg) + (reg.size / bits_per_address)) end end
Shifts out a stream of bit objects corresponding to the size of the container. i.e. calling this on a 32-bit container this will pass back 32 bit objects. If there are holes then a dummy bit object will be returned that is not writable and which will always read as 0.
The index is also returned as a second argument. Note that the position property of the bit is not updated to reflect its position within the container (it will return its position with its parent register), therefore the index should be used if the calling code needs to work out the bit position within the container.
# File lib/origen/registers/container.rb, line 229 def shift_out_left size.times do |i| yield(bit_at_position(size - i - 1), i) end end
Shifts out a stream of bit objects corresponding to the size of the container. i.e. calling this on a 32-bit container this will pass back 32 bit objects. If there are holes then a dummy bit object will be returned that is not writable and which will always read as 0.
The index is also returned as a second argument. Note that the position property of the bit is not updated to reflect its position within the container (it will return its position with its parent register), therefore the index should be used if the calling code needs to work out the bit position within the container.
# File lib/origen/registers/container.rb, line 246 def shift_out_right size.times do |i| yield(bit_at_position(i), i) end end