Class: Origen::Registers::Container
- Defined in:
- lib/origen/registers/container.rb
Overview
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
Instance Attribute Summary collapse
-
#bits_per_address ⇒ Object
readonly
The number of bits represented by an address increment of the contained registers.
-
#owned_by ⇒ Object
Set this to a string or an array of strings that represents the name of the object that owns the container.
-
#regs ⇒ Object
(also: #registers)
readonly
Returns the currently held registers.
-
#size ⇒ Object
readonly
The size of the container in bits.
Instance Method Summary collapse
-
#[](i) ⇒ Object
Returns the bit at the given bit position if it exists, otherwise returns an un-writable bit.
-
#add(reg, options = {}) ⇒ Object
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.
-
#address ⇒ Object
(also: #addr)
Returns the aligned address of the container based on the address of the currently contained registers.
- #address_of_reg(reg) ⇒ Object private
- #big_endian? ⇒ Boolean
-
#bit_at_position(i) ⇒ Object
Returns the bit at the given bit position if it exists, otherwise returns an un-writable bit.
- #bit_shift_for_reg(reg) ⇒ Object private
-
#byte_enable ⇒ Object
Returns the byte enable required to update the contained registers.
-
#clear_flags ⇒ Object
Call the clear_flags on all contained registers.
- #contains_bits? ⇒ Boolean
-
#data ⇒ Object
(also: #val, #value)
Returns the data held by the contained registers where the data from each register is shifted into the correct position.
-
#data_b ⇒ Object
Data bar, the ones complement of the current data value of the container.
- #dummy_bit ⇒ Object private
-
#empty ⇒ Object
Remove all registers from the container.
-
#initialize(options = {}) ⇒ Container
constructor
A new instance of Container.
- #little_endian? ⇒ Boolean
- #local_addr_for_reg(reg) ⇒ Object private
-
#owned_by?(name) ⇒ Boolean
Proxies to the Reg#owned_by? method.
-
#owner ⇒ Object
Returns the owner of the contained registers (assumed to be the same for all).
- #reg_contains_position?(reg, position) ⇒ Boolean private
- #shift_for_reg(reg) ⇒ Object private
-
#shift_out_left ⇒ Object
(also: #shift_out_left_with_index)
Shifts out a stream of bit objects corresponding to the size of the container.
-
#shift_out_right ⇒ Object
(also: #shift_out_right_with_index)
Shifts out a stream of bit objects corresponding to the size of the container.
Constructor Details
#initialize(options = {}) ⇒ Container
Returns a new instance of Container.
89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/origen/registers/container.rb', line 89 def initialize( = {}) = { size: 32, endian: :big, bits_per_address: 8 }.merge() @size = [:size] @endian = [:endian] @owned_by = [:owned_by] @bits_per_address = [:bits_per_address] @regs = [] @addresses = {} end |
Instance Attribute Details
#bits_per_address ⇒ Object (readonly)
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.
72 73 74 |
# File 'lib/origen/registers/container.rb', line 72 def bits_per_address @bits_per_address end |
#owned_by ⇒ Object
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).
80 81 82 |
# File 'lib/origen/registers/container.rb', line 80 def owned_by @owned_by end |
#regs ⇒ Object (readonly) Also known as: registers
Returns the currently held registers
74 75 76 |
# File 'lib/origen/registers/container.rb', line 74 def regs @regs end |
#size ⇒ Object (readonly)
The size of the container in bits
68 69 70 |
# File 'lib/origen/registers/container.rb', line 68 def size @size end |
Instance Method Details
#[](i) ⇒ Object
Returns the bit at the given bit position if it exists, otherwise returns an un-writable bit
273 274 275 |
# File 'lib/origen/registers/container.rb', line 273 def [](i) bit_at_position(i) end |
#add(reg, options = {}) ⇒ Object
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.
110 111 112 113 114 115 116 |
# File 'lib/origen/registers/container.rb', line 110 def add(reg, = {}) @regs << reg addr = [:address] || [:addr] @addresses[reg] = addr if addr @regs.sort_by! { |reg| address_of_reg(reg) } self end |
#address ⇒ Object Also known as: addr
Returns the aligned address of the container based on the address of the currently contained registers
173 174 175 176 177 178 179 |
# 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 |
#address_of_reg(reg) ⇒ 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.
119 120 121 |
# File 'lib/origen/registers/container.rb', line 119 def address_of_reg(reg) @addresses[reg] || reg.address end |
#big_endian? ⇒ Boolean
211 212 213 |
# File 'lib/origen/registers/container.rb', line 211 def big_endian? @endian == :big end |
#bit_at_position(i) ⇒ Object
Returns the bit at the given bit position if it exists, otherwise returns an un-writable bit
255 256 257 258 259 260 261 262 |
# 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 |
#bit_shift_for_reg(reg) ⇒ 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.
207 208 209 |
# File 'lib/origen/registers/container.rb', line 207 def bit_shift_for_reg(reg) shift_for_reg(reg) * bits_per_address end |
#byte_enable ⇒ Object
Returns the byte enable required to update the contained registers.
183 184 185 186 187 188 189 190 |
# 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 |
#clear_flags ⇒ Object
Call the clear_flags on all contained registers
283 284 285 |
# File 'lib/origen/registers/container.rb', line 283 def clear_flags @regs.each(&:clear_flags) end |
#contains_bits? ⇒ Boolean
103 104 105 |
# File 'lib/origen/registers/container.rb', line 103 def contains_bits? true end |
#data ⇒ Object Also known as: val, value
Returns the data held by the contained registers where the data from each register is shifted into the correct position
125 126 127 128 129 130 131 |
# 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_b ⇒ Object
Data bar, the ones complement of the current data value of the container
137 138 139 |
# File 'lib/origen/registers/container.rb', line 137 def data_b ~data & ((1 << size) - 1) end |
#dummy_bit ⇒ 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.
278 279 280 |
# File 'lib/origen/registers/container.rb', line 278 def dummy_bit @dummy_bit ||= Bit.new(self, 0, writable: false) end |
#empty ⇒ Object
Remove all registers from the container
142 143 144 145 146 |
# File 'lib/origen/registers/container.rb', line 142 def empty @regs = [] @addresses = {} self end |
#little_endian? ⇒ Boolean
215 216 217 |
# File 'lib/origen/registers/container.rb', line 215 def little_endian? !big_endian? end |
#local_addr_for_reg(reg) ⇒ 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.
193 194 195 |
# 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 |
#owned_by?(name) ⇒ Boolean
Proxies to the Reg#owned_by? method
157 158 159 160 161 162 163 164 165 166 167 168 169 |
# 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 |
#owner ⇒ Object
Returns the owner of the contained registers (assumed to be the same for all)
150 151 152 153 154 |
# File 'lib/origen/registers/container.rb', line 150 def owner unless @regs.empty? @regs.first.owner end end |
#reg_contains_position?(reg, position) ⇒ Boolean
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.
265 266 267 268 269 |
# 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 |
#shift_for_reg(reg) ⇒ 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.
198 199 200 201 202 203 204 |
# 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 |
#shift_out_left ⇒ Object Also known as: shift_out_left_with_index
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.
229 230 231 232 233 |
# 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 |
#shift_out_right ⇒ Object Also known as: shift_out_right_with_index
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.
246 247 248 249 250 |
# File 'lib/origen/registers/container.rb', line 246 def shift_out_right size.times do |i| yield(bit_at_position(i), i) end end |