Class: CrossOrigen::IpXact

Inherits:
XMLDoc
  • Object
show all
Defined in:
lib/cross_origen/ip_xact.rb

Defined Under Namespace

Classes: AddressBlock, AddressSpace, MemoryMaps

Constant Summary

Constants inherited from XMLDoc

XMLDoc::HTML_SANITIZATION_CONFIG, XMLDoc::HTML_TRANSFORMER, XMLDoc::HTML_TRANSFORMS

Instance Attribute Summary

Attributes inherited from XMLDoc

#creation_info, #import_info, #owner

Instance Method Summary collapse

Methods inherited from XMLDoc

#extract, #fetch, #initialize, #pre_sanitize, #to_html, #to_markdown, #try

Constructor Details

This class inherits a constructor from CrossOrigen::XMLDoc

Instance Method Details

#doc(path, options = {}) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/cross_origen/ip_xact.rb', line 99

def doc(path, options = {})
  # If a fragment of IP-XACT is given, then wrap it with a valid header and we will try our best
  if options[:fragment]
    require 'nokogiri'

    content = %(
<?xml version="1.0"?>
<spirit:component xmlns:spirit="http://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="$REGMEM_HOME/builder/ipxact/schema/ipxact
      $REGMEM_HOME/builder/ipxact/schema/ipxact/index.xsd">
    #{File.read(path)}
</spirit:component>
    )
    yield Nokogiri::XML(content)
  else
    super
  end
end

#import(file, options = {}) ⇒ Object

Import/reader that currently only supports creating registers and bit fields



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/cross_origen/ip_xact.rb', line 10

def import(file, options = {}) # rubocop:disable CyclomaticComplexity
  require 'kramdown'

  filename = Pathname.new(file).basename('.*').to_s

  unless options[:refresh] || CrossOrigen.refresh?
    return if owner.import(filename, allow_missing: true)
  end

  model = CrossOrigen::Model.new

  address_spaces = {}

  doc(file, options) do |doc|
    doc.xpath('//spirit:addressSpaces/spirit:addressSpace').each do |addr_space|
      name = fetch addr_space.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
      range = fetch addr_space.at_xpath('spirit:range'), get_text: true, to_dec: true
      width = fetch addr_space.at_xpath('spirit:width'), get_text: true, to_i: true
      address_spaces[name] = AddressSpace.new(name, range, width)
    end
    open_memory_map(doc) do |mem_map|
      if mem_map
        mem_map_name = fetch mem_map.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
        if mem_map_name.to_s.empty?
          mem_map_obj = model
        else
          model.sub_block mem_map_name
          mem_map_obj = model.send(mem_map_name)
        end
        addr_blocks = mem_map.xpath('spirit:addressBlock')
      else
        mem_map_obj = model
        addr_blocks = doc.xpath('//spirit:addressBlock')
      end
      addr_blocks.each do |addr_block|
        name = fetch addr_block.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
        base_address = fetch addr_block.at_xpath('spirit:baseAddress'), get_text: true, to_dec: true
        range = fetch addr_block.at_xpath('spirit:range'), get_text: true, to_dec: true
        width = fetch addr_block.at_xpath('spirit:width'), get_text: true, to_i: true
        if name.to_s.empty?
          addr_block_obj = mem_map_obj
        else
          mem_map_obj.sub_block name, base_address: base_address, range: range, lau: width
          addr_block_obj = mem_map_obj.send(name)
        end
        addr_block.xpath('spirit:register').each do |register|
          name = fetch register.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
          size = fetch register.at_xpath('spirit:size'), get_text: true, to_i: true
          addr_offset = fetch register.at_xpath('spirit:addressOffset'), get_text: true, to_dec: true
          access = fetch register.at_xpath('spirit:access'), get_text: true
          reset_value = fetch register.at_xpath('spirit:reset/spirit:value'), get_text: true, to_dec: true
          reset_mask = fetch register.at_xpath('spirit:reset/spirit:mask'), get_text: true, to_dec: true
          if [reset_value, reset_mask].include? nil
            # Set default values for some register attributes
            reset_value, reset_mask = 0, 0
          else
            # Do a logical bitwise AND with the reset value and mask
            reset_value = reset_value & reset_mask
          end
          addr_block_obj.reg name, addr_offset, size: size, access: access, description: reg_description(register) do |reg|
            register.xpath('spirit:field').each do |field|
              name = fetch field.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
              bit_offset = fetch field.at_xpath('spirit:bitOffset'), get_text: true, to_i: true
              bit_width = fetch field.at_xpath('spirit:bitWidth'), get_text: true, to_i: true
              access = fetch field.at_xpath('spirit:access'), get_text: true
              if access =~ /\S+\-\S+/
                access = access[/^(\S)/, 1] + access[/\-(\S)\S+$/, 1]
                access = access.downcase.to_sym
              else
                # default to read-write if access is not specified
                access = :rw
              end
              range = nil
              if bit_width == 1
                range = bit_offset
              else
                range = (bit_offset + bit_width - 1)..bit_offset
              end
              reg.bit range, name, reset: reset_value[range], access: access, description: bit_description(field)
            end
          end
        end
      end
    end
  end
  model.export(filename, include_timestamp: CrossOrigen.include_timestamp?)
  owner.import(filename)
end

#owner_to_xml(options = {}) ⇒ Object

Returns a string representing the owner object in IP-XACT XML



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/cross_origen/ip_xact.rb', line 120

def owner_to_xml(options = {})
  require 'nokogiri'

  options = {
    include_bit_field_values: true
  }.merge(options)

  @format = options[:format]

  schemas = [
    'http://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4',
    'http://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4/index.xsd'
  ]
  if uvm?
    schemas << '$IREG_GEN/XMLSchema/SPIRIT/VendorExtensions.xsd'
  end

  headers = {
    'xmlns:spirit'       => 'http://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4',
    'xmlns:xsi'          => 'http://www.w3.org/2001/XMLSchema-instance',
    'xsi:schemaLocation' => schemas.join(' ')
  }
  if uvm?
    headers['xmlns:vendorExtensions'] = '$IREG_GEN/XMLSchema/SPIRIT'
  end

  builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
    spirit = xml['spirit']
    spirit.component(headers) do
      spirit.vendor options[:vendor] || 'Origen'
      spirit.library options[:library] || 'Origen'
      # I guess this should really be the register owner's owner's name?
      spirit.name try(:ip_name) || owner.class.to_s.split('::').last
      spirit.version try(:ip_version, :version, :revision)
      spirit.memoryMaps do
        memory_maps.each do |map_name, _map|
          spirit.memoryMap do
            spirit.name map_name
            address_blocks do |domain_name, _domain, sub_block|
              spirit.addressBlock do
                if sub_block == owner
                  spirit.name nil
                  spirit.baseAddress 0.to_hex
                else
                  spirit.name address_block_name(domain_name, sub_block)
                  spirit.baseAddress sub_block.base_address.to_hex
                end
                spirit.range range(sub_block)
                spirit.width width(sub_block)
                sub_block.regs.each do |name, reg|
                  # Required for now to ensure that the current value is the reset value
                  reg.reset
                  spirit.register do
                    spirit.name name
                    spirit.description try(reg, :name_full, :full_name)
                    spirit.addressOffset reg.offset.to_hex
                    spirit.size reg.size
                    if reg.bits.any?(&:writable?)
                      spirit.access 'read-write'
                    else
                      spirit.access 'read-only'
                    end
                    spirit.reset do
                      spirit.value reg.data.to_hex
                      spirit.mask mask(reg).to_hex
                    end
                    reg.named_bits do |name, bits|
                      spirit.field do
                        spirit.name name
                        spirit.description try(bits, :brief_description, :name_full, :full_name)
                        spirit.bitOffset bits.position
                        spirit.bitWidth bits.size
                        spirit.access bits.access
                        if options[:include_bit_field_values]
                          if bits.bit_value_descriptions[0]
                            bits.bit_value_descriptions.each do |val, desc|
                              spirit.values do
                                spirit.value val.to_hex
                                spirit.name "val_#{val.to_hex}"
                                spirit.description desc
                              end
                            end
                          end
                        end
                        if uvm?
                          spirit.vendorExtensions do
                            xml['vendorExtensions'].hdl_path bits.path(relative_to: sub_block)
                          end
                        end
                      end
                    end
                  end
                end
                if uvm?
                  spirit.vendorExtensions do
                    xml['vendorExtensions'].hdl_path sub_block.path(relative_to: owner)
                  end
                end
              end
            end
          end
        end
      end
    end
  end
  builder.to_xml
end