lib/cross_origen/ip_xact.rb
# Import/reader that currently only supports creating registers and bit fields
Import/reader that currently only supports creating registers and bit fields
Import / reader that currently only supports creating registers and bit fields
def import(file, options = {}) 
      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
              if register.at_xpath('spirit:reset').nil?
                reset_value = 0
              else
                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.nil?
                  reset_value = 0
                  Origen.log.warning "Register {name.upcase} was defined as having a reset, but did not have a defined reset value.  This is not compliant with IP-XACT standard."
                  Origen.log.warning "The reset value for {name.upcase} has been defined as 0x0 as a result."
                elsif reset_mask.nil?
                else
                  reset_value = reset_value & reset_mask
                end
              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
                  xml_access = fetch field.at_xpath('spirit:access'), get_text: true
                  if xml_access =~ /\S+\-\S+/ || xml_access == 'writeOnce'
                     First get the base access type, ie: read-write, read-only, etc.
                     base_access = fetch field.at_xpath('spirit:access'), get_text: true
                    base_access = xml_access
                     Next grab any modified write values or read actions
                    mod_write = fetch field.at_xpath('spirit:modifiedWriteValue'), get_text: true
                    read_action = fetch field.at_xpath('spirit:readAction'), get_text: true
                     Using base_access, mod_write, and read_action, look up the corresponding access
                     acronym from access_hash, noting it is not possible to differentiate write-only
                     from write-only, read zero and read-write from dc.
                     Matched needs to be tracked, as there is no way to differentiate :rw and :dc in IP-XACT.
                     Everything imported will default to :rw, never :dc.
                    matched = false
                    @@access_hash.each_key do |key|
                      if @@access_hash[key][:base] == base_access && @@access_hash[key][:write] == mod_write && @@access_hash[key][:read] == read_action && !matched
                        access = key.to_sym
                        matched = true
                      end
                    end
                   Older IP-XACT standards appear to also accept short acronyms like "ro", "w1c", "rw",
                   etc.
                  elsif xml_access =~ /\S+/
                    access = xml_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, options)
    end
def import ( file , options = { } ) 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 if register . at_xpath ( 'spirit:reset' ) . nil? reset_value = 0 else 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 . nil? reset_value = 0 Origen . log . warning "Register #{name.upcase} was defined as having a reset, but did not have a defined reset value.  This is not compliant with IP-XACT standard." Origen . log . warning "The reset value for #{name.upcase} has been defined as 0x0 as a result." elsif reset_mask . nil? else reset_value = reset_value & reset_mask end 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 xml_access = fetch field . at_xpath ( 'spirit:access' ) , get_text : true if xml_access =~ / \S + \- \S + / || xml_access == 'writeOnce' base_access = xml_access mod_write = fetch field . at_xpath ( 'spirit:modifiedWriteValue' ) , get_text : true read_action = fetch field . at_xpath ( 'spirit:readAction' ) , get_text : true matched = false @@access_hash . each_key do | key | if @@access_hash [ key ] [ :base ] == base_access && @@access_hash [ key ] [ :write ] == mod_write && @@access_hash [ key ] [ :read ] == read_action && ! matched access = key . to_sym matched = true end end elsif xml_access =~ / \S + / access = xml_access . downcase . to_sym else 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 , options ) end
Import/reader that currently only supports creating registers and bit fields
Import / reader that currently only supports creating registers and bit fields
# rubocop:disable CyclomaticComplexity # Determine if a reset is defined for the register # If a reset does not exist, need to set the reset_value to 0, as Origen does not (yet) have a concept # of a register without a reset. # If a reset exists, determine the reset_value (required) and reset_mask (if defined) # Issue #8 fix - reset_mask is optional, keep reset value as imported when a mask is not defined. # Only perform AND-ing if mask is defined.  Only zero-out the reset_value if reset_value was nil. # Set default for reset_value attribute if none was provided and issue a warning. # If mask is undefined, leave reset_value alone. # Do a logical bitwise AND with the reset value and mask # Future expansion: pull in HDL path as abs_path in Origen. # Newer IP-XACT standards list access as < read or write>-< descriptor >, such as # "read-write", "read-only", or "read-writeOnce" # This filter alone is not capable of interpreting the 1685-2009 (and 2014).  Therefore # must reverse-interpret the content of access_hash (see top of file). # # First get the base access type, ie: read-write, read-only, etc. # base_access = fetch field.at_xpath('spirit:access'), get_text: true # Next grab any modified write values or read actions # Using base_access, mod_write, and read_action, look up the corresponding access # acronym from access_hash, noting it is not possible to differentiate write-only # from write-only, read zero and read-write from dc. # # Matched needs to be tracked, as there is no way to differentiate :rw and :dc in IP-XACT. # Everything imported will default to :rw, never :dc. # Older IP-XACT standards appear to also accept short acronyms like "ro", "w1c", "rw", # etc. # default to read-write if access is not specified
file
<not_specific>
options
<not_specific>