loading
Generated 2021-05-25T12:52:36-05:00

All Files ( 88.48% covered at 52.56 hits/line )

8 files in total.
625 relevant lines, 553 lines covered and 72 lines missed. ( 88.48% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
lib/cross_origen.rb 85.48 % 121 62 53 9 4.50
lib/cross_origen/cmsis_svd.rb 97.85 % 155 93 91 2 39.10
lib/cross_origen/design_sync.rb 26.67 % 54 30 8 22 0.27
lib/cross_origen/headers.rb 100.00 % 21 10 10 0 1.00
lib/cross_origen/ip_xact.rb 91.13 % 532 248 226 22 29.29
lib/cross_origen/ralf.rb 100.00 % 15 7 7 0 1.00
lib/cross_origen/xml_doc.rb 84.68 % 252 111 94 17 189.25
lib/cross_origen_dev/dut.rb 100.00 % 121 64 64 0 9.97

lib/cross_origen.rb

85.48% lines covered

62 relevant lines. 53 lines covered and 9 lines missed.
    
  1. 1 require 'origen'
  2. 1 require_relative '../config/application.rb'
  3. 1 module CrossOrigen
  4. 1 autoload :XMLDoc, 'cross_origen/xml_doc'
  5. 1 autoload :Headers, 'cross_origen/headers'
  6. 1 autoload :Ralf, 'cross_origen/ralf'
  7. 1 autoload :IpXact, 'cross_origen/ip_xact'
  8. 1 autoload :DesignSync, 'cross_origen/design_sync'
  9. 1 autoload :CMSISSVD, 'cross_origen/cmsis_svd'
  10. # Basic object that is used to capture imported data and then export/save
  11. # it to Origen format
  12. 1 class Model
  13. 1 include Origen::Model
  14. end
  15. # Returns true if the --refresh switch was passed to the current Origen command
  16. 1 def self.refresh?
  17. 15 @refresh || false
  18. end
  19. 1 def self.include_timestamp?
  20. 4 instance_variable_defined?(:@include_timestamp) ? @include_timestamp : true
  21. end
  22. 1 def self.include_timestamp=(val)
  23. 19 @include_timestamp = val
  24. end
  25. 1 def instance_respond_to?(method_name)
  26. public_methods.include?(method_name)
  27. end
  28. 1 def cr_import(options = {})
  29. options = {
  30. 19 include_timestamp: true
  31. }.merge(options)
  32. 19 CrossOrigen.include_timestamp = options[:include_timestamp]
  33. 19 file = cr_file(options)
  34. 19 cr_translator(file, options).import(file, options)
  35. end
  36. 1 def to_ralf(options = {})
  37. 1 cr_ralf.owner_to_ralf(options)
  38. end
  39. 1 def to_ip_xact(options = {})
  40. 4 cr_ip_xact.owner_to_xml(options)
  41. end
  42. 1 alias_method :to_ipxact, :to_ip_xact
  43. 1 def to_header(options = {})
  44. 1 cr_headers.owner_to_header(options)
  45. end
  46. # Tries the given methods and returns the first one to return a value,
  47. # ultimately returns nil if no value is found.
  48. 1 def cr_try(*methods)
  49. 2 methods.each do |method|
  50. 3 if self.respond_to?(method)
  51. 2 val = send(method)
  52. 2 return val if val
  53. end
  54. end
  55. nil
  56. end
  57. # Returns an instance of the DesignSync interface
  58. 1 def cr_design_sync
  59. @cr_design_sync ||= DesignSync.new(self)
  60. end
  61. 1 def cr_headers
  62. 1 @cr_headers ||= Headers.new(self)
  63. end
  64. 1 def cr_ralf
  65. 1 @cr_ralf ||= Ralf.new(self)
  66. end
  67. 1 def cr_ip_xact
  68. 22 @cr_ip_xact ||= IpXact.new(self)
  69. end
  70. 1 def cr_cmsis_svd
  71. 2 @cr_cmsis_svd ||= CMSISSVD.new(self)
  72. end
  73. 1 private
  74. # Returns an instance of the translator for the format of the given file
  75. 1 def cr_translator(file, options = {})
  76. 19 snippet = IO.read(file, 2000) # Read first 2000 characters
  77. 19 case snippet
  78. when /spiritconsortium/
  79. 17 cr_ip_xact
  80. when /CMSIS-SVD.xsd/
  81. 2 cr_cmsis_svd
  82. else
  83. # Give IP-XACT another opportunity if it looks like partial IP-XACT doc
  84. if snippet =~ /<spirit:register>/
  85. options[:fragment] = true
  86. cr_ip_xact
  87. else
  88. fail "Unknown file format for file: #{file}"
  89. end
  90. end
  91. end
  92. # Returns a local path to the given file defined by the options.
  93. 1 def cr_file(options = {})
  94. 19 if options[:path]
  95. 19 options[:path]
  96. elsif options[:vault]
  97. cr_design_sync.fetch(options)
  98. else
  99. fail 'You must supply a :path or :vault option pointing to the import file!'
  100. end
  101. end
  102. end

lib/cross_origen/cmsis_svd.rb

97.85% lines covered

93 relevant lines. 91 lines covered and 2 lines missed.
    
  1. 1 module CrossOrigen
  2. 1 class CMSISSVD < XMLDoc
  3. 1 def import(file, options = {}) # rubocop:disable CyclomaticComplexity
  4. 2 filename = Pathname.new(file).basename('.*').to_s
  5. 2 unless options[:refresh] || CrossOrigen.refresh?
  6. return if owner.import(filename, allow_missing: true)
  7. end
  8. 2 model = CrossOrigen::Model.new
  9. 2 doc(file, options) do |doc|
  10. 2 peripherals = peripherals(doc)
  11. 8 groups = peripherals.values.map { |v| v[:group] }.uniq
  12. 4 groups.each { |group| model.sub_block group }
  13. 2 peripherals.each do |name, attrs|
  14. 6 base = attrs[:group] ? model.send(attrs[:group]) : model
  15. 6 block = base.sub_block name, base_address: attrs[:base_address]
  16. 6 if attrs[:parent]
  17. 4 add_registers(block, find_peripheral_by_name(doc, attrs[:parent]))
  18. end
  19. 6 add_registers(block, find_peripheral_by_name(doc, name))
  20. end
  21. end
  22. 2 model.export(filename, include_timestamp: CrossOrigen.include_timestamp?)
  23. 2 owner.import(filename)
  24. end
  25. 1 private
  26. 1 def add_registers(model, peripheral)
  27. 10 peripheral.xpath('registers/register').each do |r|
  28. 48 name = extract(r, 'name')
  29. 48 di = extract(r, 'dim', format: :integer)
  30. 48 dim = !!di
  31. 48 if dim
  32. 6 dinc = extract(r, 'dimIncrement', format: :integer)
  33. 6 dvals = extract(r, 'dimIndex').split(',')
  34. else
  35. 42 di = 1
  36. end
  37. 48 offset = extract(r, 'addressOffset', format: :integer, hex: true)
  38. 48 size = extract(r, 'size', format: :integer)
  39. 48 reset = extract(r, 'resetValue', format: :integer, hex: true)
  40. 48 desc = (extract(r, 'description') || '').gsub("'", %q(\\\'))
  41. 48 di.times do |i|
  42. 66 if dim
  43. 24 n = name.sub('[%s]', dvals[i])
  44. 24 addr = offset + (i * dinc)
  45. else
  46. 42 n = name
  47. 42 addr = offset
  48. end
  49. opts = {
  50. 66 size: size,
  51. description: desc
  52. }
  53. 66 opts[:reset] = reset if reset
  54. 66 reg_name = n.downcase.symbolize
  55. # The register could already exist if it was added by a parent peripheral definition and now it
  56. # is redefined/overridden by a descendent peripheral
  57. 66 model.del_reg(reg_name) if model.has_reg?(reg_name)
  58. 66 model.reg reg_name, addr, opts do |reg|
  59. 66 r.xpath('fields/field').each do |b|
  60. 120 bn = extract(b, 'name')
  61. 120 unless bn == 'RESERVED'
  62. 120 bn = bn.to_s.downcase.symbolize
  63. 120 lsb = extract(b, 'lsb', format: :integer)
  64. 120 msb = extract(b, 'msb', format: :integer)
  65. 120 unless lsb
  66. 120 lsb = extract(b, 'bitOffset', format: :integer)
  67. 120 if lsb
  68. msb = lsb + extract(b, 'msb', format: :integer) - 1
  69. end
  70. end
  71. 120 unless lsb
  72. 120 range = extract(b, 'bitRange')
  73. 120 range =~ /\[(\d+):(\d+)\]/
  74. 120 lsb = Regexp.last_match(2).to_i
  75. 120 msb = Regexp.last_match(1).to_i
  76. end
  77. 120 access = extract(b, 'access')
  78. 120 desc = (extract(r, 'description') || '').gsub("'", %q(\\\'))
  79. 120 case access
  80. when 'read-only'
  81. 18 ac = :ro
  82. else
  83. 102 ac = :rw
  84. end
  85. 120 if lsb == msb
  86. 60 reg.bit lsb, bn, access: ac, description: desc
  87. else
  88. 60 reg.bit msb..lsb, bn, access: ac, description: desc
  89. end
  90. end
  91. end
  92. end
  93. end
  94. end
  95. end
  96. 1 def find_peripheral_by_name(doc, pname)
  97. 10 doc.xpath('device/peripherals/peripheral').find do |peripheral|
  98. 16 pname == name(peripheral)
  99. end
  100. end
  101. 1 def clean_name(name)
  102. 32 name = name.to_s
  103. 32 unless name.empty?
  104. 28 name.downcase.symbolize
  105. end
  106. end
  107. 1 def name(peripheral)
  108. 22 clean_name(fetch(peripheral.xpath('name'), get_text: true))
  109. end
  110. 1 def group_name(peripheral)
  111. 6 clean_name(fetch(peripheral.xpath('groupName'), get_text: true))
  112. end
  113. 1 def parent(peripheral)
  114. 6 a = peripheral.attributes['derivedFrom']
  115. 6 a ? clean_name(a.value) : nil
  116. end
  117. 1 def base_address(peripheral)
  118. 6 extract(peripheral, 'baseAddress', format: :integer, hex: true)
  119. end
  120. 1 def peripherals(doc)
  121. 2 peripherals = {}
  122. 2 doc.xpath('device/peripherals/peripheral').each do |peripheral|
  123. 6 peripherals[name(peripheral)] = {
  124. group: group_name(peripheral),
  125. parent: parent(peripheral),
  126. base_address: base_address(peripheral)
  127. }
  128. end
  129. # Inherit missing values from parents...
  130. 2 p = {}
  131. 2 peripherals.each do |k, v|
  132. 6 v[:group] ||= peripherals[v[:parent]][:group]
  133. 6 v[:base_address] ||= peripherals[v[:parent]][:base_address]
  134. 6 p[k] = v
  135. end
  136. 2 p
  137. end
  138. end
  139. end

lib/cross_origen/design_sync.rb

26.67% lines covered

30 relevant lines. 8 lines covered and 22 lines missed.
    
  1. 1 module CrossOrigen
  2. # Driver for talking to DesignSync
  3. 1 class DesignSync
  4. 1 require 'digest/sha1'
  5. # Returns the object that included the CrossOrigen module
  6. 1 attr_reader :owner
  7. 1 def initialize(owner)
  8. @owner = owner
  9. end
  10. 1 def driver
  11. @driver ||= Origen::Utility::DesignSync.new
  12. end
  13. # Returns a full path to the Design Sync import (cache) directory
  14. 1 def import_dir
  15. return @import_dir if @import_dir
  16. @import_dir = "#{Origen.app.workspace_manager.imports_directory}/design_sync"
  17. FileUtils.mkdir_p(@import_dir) unless File.exist?(@import_dir)
  18. @import_dir
  19. end
  20. # This will be called if the user has supplied a :vault in the rs_import options. The corresponding
  21. # version of the file will be returned from the cache if it already exists locally, otherwise it
  22. # will be imported.
  23. #
  24. # This method returns a full path to the local cache copy of the file.
  25. 1 def fetch(options = {})
  26. unless options[:version]
  27. puts 'You must supply a :version number (or tag) when importing data from Design Sync'
  28. exit 1
  29. end
  30. v = options[:vault]
  31. f = v.split('/').last
  32. vault = v.sub(/\/#{f}$/, '')
  33. # Consider that similarly named files could exist in different vaults, so attach
  34. # a representation of the vault to the filename
  35. vault_hash = Digest::SHA1.hexdigest(vault)
  36. dir = "#{import_dir}/#{vault_hash}-#{f}"
  37. file = "#{dir}/#{options[:version]}"
  38. if f =~ /.*\.(.*)/
  39. file += ".#{Regexp.last_match[1]}"
  40. end
  41. if !File.exist?(file) || options[:force]
  42. FileUtils.mkdir_p(dir) unless File.exist?(dir)
  43. driver.import(f, vault, options[:version], dir)
  44. FileUtils.mv("#{dir}/#{f}", file)
  45. end
  46. file
  47. end
  48. end
  49. end

lib/cross_origen/headers.rb

100.0% lines covered

10 relevant lines. 10 lines covered and 0 lines missed.
    
  1. 1 module CrossOrigen
  2. 1 class Headers
  3. # Returns the object that included the CrossOrigen module
  4. 1 attr_reader :owner
  5. 1 def initialize(owner)
  6. 1 @owner = owner
  7. end
  8. # Returns a string representing the owner as a C header
  9. 1 def owner_to_header(_options = {})
  10. 1 Origen.compile("#{path_to_templates}/headers/default.h.erb", scope: owner)
  11. end
  12. 1 private
  13. 1 def path_to_templates
  14. 1 "#{File.expand_path(File.dirname(__FILE__))}/../../templates"
  15. end
  16. end
  17. end

lib/cross_origen/ip_xact.rb

91.13% lines covered

248 relevant lines. 226 lines covered and 22 lines missed.
    
  1. 1 module CrossOrigen
  2. 1 class IpXact < XMLDoc
  3. 1 AddressSpace = Struct.new(:name, :range, :width)
  4. 1 MemoryMaps = Struct.new(:name, :address_blocks)
  5. 1 AddressBlock = Struct.new(:name, :base_address, :range, :width)
  6. # Create a shorthand way to reference Origen Core's Bit ACCESS_CODES
  7. 1 @@access_hash = Origen::Registers::Bit.const_get(:ACCESS_CODES)
  8. # Import/reader that currently only supports creating registers and bit fields
  9. 1 def import(file, options = {}) # rubocop:disable CyclomaticComplexity
  10. 17 require 'kramdown'
  11. 17 filename = Pathname.new(file).basename('.*').to_s
  12. 17 unless options[:refresh] || CrossOrigen.refresh?
  13. 15 return if owner.import(filename, allow_missing: true)
  14. end
  15. 2 model = CrossOrigen::Model.new
  16. 2 address_spaces = {}
  17. 2 doc(file, options) do |doc|
  18. 2 doc.xpath('//spirit:addressSpaces/spirit:addressSpace').each do |addr_space|
  19. name = fetch addr_space.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
  20. range = fetch addr_space.at_xpath('spirit:range'), get_text: true, to_dec: true
  21. width = fetch addr_space.at_xpath('spirit:width'), get_text: true, to_i: true
  22. address_spaces[name] = AddressSpace.new(name, range, width)
  23. end
  24. 2 open_memory_map(doc) do |mem_map|
  25. 2 if mem_map
  26. 2 mem_map_name = fetch mem_map.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
  27. 2 if mem_map_name.to_s.empty?
  28. mem_map_obj = model
  29. else
  30. 2 model.sub_block mem_map_name
  31. 2 mem_map_obj = model.send(mem_map_name)
  32. end
  33. 2 addr_blocks = mem_map.xpath('spirit:addressBlock')
  34. else
  35. mem_map_obj = model
  36. addr_blocks = doc.xpath('//spirit:addressBlock')
  37. end
  38. 2 addr_blocks.each do |addr_block|
  39. 2 name = fetch addr_block.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
  40. 2 base_address = fetch addr_block.at_xpath('spirit:baseAddress'), get_text: true, to_dec: true
  41. 2 range = fetch addr_block.at_xpath('spirit:range'), get_text: true, to_dec: true
  42. 2 width = fetch addr_block.at_xpath('spirit:width'), get_text: true, to_i: true
  43. 2 if name.to_s.empty?
  44. 2 addr_block_obj = mem_map_obj
  45. else
  46. mem_map_obj.sub_block name, base_address: base_address, range: range, lau: width
  47. addr_block_obj = mem_map_obj.send(name)
  48. end
  49. 2 addr_block.xpath('spirit:register').each do |register|
  50. 4 name = fetch register.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
  51. 4 size = fetch register.at_xpath('spirit:size'), get_text: true, to_i: true
  52. 4 addr_offset = fetch register.at_xpath('spirit:addressOffset'), get_text: true, to_dec: true
  53. 4 access = fetch register.at_xpath('spirit:access'), get_text: true
  54. # Determine if a reset is defined for the register
  55. 4 if register.at_xpath('spirit:reset').nil?
  56. # If a reset does not exist, need to set the reset_value to 0, as Origen does not (yet) have a concept
  57. # of a register without a reset.
  58. reset_value = 0
  59. else
  60. # If a reset exists, determine the reset_value (required) and reset_mask (if defined)
  61. 4 reset_value = fetch register.at_xpath('spirit:reset/spirit:value'), get_text: true, to_dec: true
  62. 4 reset_mask = fetch register.at_xpath('spirit:reset/spirit:mask'), get_text: true, to_dec: true
  63. # Issue #8 fix - reset_mask is optional, keep reset value as imported when a mask is not defined.
  64. # Only perform AND-ing if mask is defined. Only zero-out the reset_value if reset_value was nil.
  65. 4 if reset_value.nil?
  66. # Set default for reset_value attribute if none was provided and issue a warning.
  67. reset_value = 0
  68. 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."
  69. Origen.log.warning "The reset value for #{name.upcase} has been defined as 0x0 as a result."
  70. 4 elsif reset_mask.nil?
  71. # If mask is undefined, leave reset_value alone.
  72. else
  73. # Do a logical bitwise AND with the reset value and mask
  74. 4 reset_value = reset_value & reset_mask
  75. end
  76. end
  77. # Future expansion: pull in HDL path as abs_path in Origen.
  78. 4 addr_block_obj.reg name, addr_offset, size: size, access: access, description: reg_description(register) do |reg|
  79. 4 register.xpath('spirit:field').each do |field|
  80. 60 name = fetch field.at_xpath('spirit:name'), downcase: true, to_sym: true, get_text: true
  81. 60 bit_offset = fetch field.at_xpath('spirit:bitOffset'), get_text: true, to_i: true
  82. 60 bit_width = fetch field.at_xpath('spirit:bitWidth'), get_text: true, to_i: true
  83. 60 xml_access = fetch field.at_xpath('spirit:access'), get_text: true
  84. # Newer IP-XACT standards list access as < read or write>-< descriptor >, such as
  85. # "read-write", "read-only", or "read-writeOnce"
  86. 60 if xml_access =~ /\S+\-\S+/ || xml_access == 'writeOnce'
  87. # This filter alone is not capable of interpreting the 1685-2009 (and 2014). Therefore
  88. # must reverse-interpret the content of access_hash (see top of file).
  89. #
  90. # First get the base access type, ie: read-write, read-only, etc.
  91. # base_access = fetch field.at_xpath('spirit:access'), get_text: true
  92. 30 base_access = xml_access
  93. # Next grab any modified write values or read actions
  94. 30 mod_write = fetch field.at_xpath('spirit:modifiedWriteValue'), get_text: true
  95. 30 read_action = fetch field.at_xpath('spirit:readAction'), get_text: true
  96. # Using base_access, mod_write, and read_action, look up the corresponding access
  97. # acronym from access_hash, noting it is not possible to differentiate write-only
  98. # from write-only, read zero and read-write from dc.
  99. #
  100. # Matched needs to be tracked, as there is no way to differentiate :rw and :dc in IP-XACT.
  101. # Everything imported will default to :rw, never :dc.
  102. 30 matched = false
  103. 30 @@access_hash.each_key do |key|
  104. 840 if @@access_hash[key][:base] == base_access && @@access_hash[key][:write] == mod_write && @@access_hash[key][:read] == read_action && !matched
  105. 30 access = key.to_sym
  106. 30 matched = true
  107. end
  108. end
  109. # Older IP-XACT standards appear to also accept short acronyms like "ro", "w1c", "rw",
  110. # etc.
  111. 30 elsif xml_access =~ /\S+/
  112. 30 access = xml_access.downcase.to_sym
  113. else
  114. # default to read-write if access is not specified
  115. access = :rw
  116. end
  117. 60 range = nil
  118. 60 if bit_width == 1
  119. 58 range = bit_offset
  120. else
  121. 2 range = (bit_offset + bit_width - 1)..bit_offset
  122. end
  123. 60 reg.bit range, name, reset: reset_value[range], access: access, description: bit_description(field)
  124. end
  125. end
  126. end
  127. end
  128. end
  129. end
  130. 2 model.export(filename, include_timestamp: CrossOrigen.include_timestamp?)
  131. 2 owner.import(filename, options)
  132. end
  133. 1 def doc(path, options = {})
  134. # If a fragment of IP-XACT is given, then wrap it with a valid header and we will try our best
  135. 2 if options[:fragment]
  136. require 'nokogiri'
  137. content = %(
  138. <?xml version="1.0"?>
  139. <spirit:component xmlns:spirit="https://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4"
  140. xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
  141. xsi:schemaLocation="$REGMEM_HOME/builder/ipxact/schema/ipxact
  142. $REGMEM_HOME/builder/ipxact/schema/ipxact/index.xsd">
  143. #{File.read(path)}
  144. </spirit:component>
  145. )
  146. yield Nokogiri::XML(content)
  147. else
  148. 2 super
  149. end
  150. end
  151. # Returns a string representing the owner object in IP-XACT XML
  152. # Usable / Available options:
  153. # :vendor = Company name/web address, ex: 'nxp.com'
  154. # :library = IP Library
  155. # :schema = '1685-2009' or default of Spirit 1.4 (when no :schema option passed)
  156. # :bus_interface = only 'AMBA3' supported at this time
  157. # :mmap_name = Optionally set the memoryMap name to something other than the module name
  158. # :mmap_ref = memoryMapRef name, ex: 'UserMap'
  159. # :addr_block_name = addressBlock -> Name, ex: 'ATX'
  160. 1 def owner_to_xml(options = {})
  161. 4 require 'nokogiri'
  162. options = {
  163. 4 include_bit_field_values: true
  164. }.merge(options)
  165. 4 @format = options[:format]
  166. # Compatible schemas: Spirit 1.4, 1685-2009
  167. # Assume Spirit 1.4 if no schema provided
  168. 4 if options[:schema] == '1685-2009' # Magillem tool uses alternate schema
  169. schemas = [
  170. 2 'https://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009',
  171. 'https://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009/index.xsd'
  172. ]
  173. else # Assume Spirit 1.4 if not
  174. schemas = [
  175. 2 'https://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4',
  176. 'https://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4/index.xsd'
  177. ]
  178. end
  179. 4 if uvm? && !(options[:schema] == '1685-2009')
  180. 1 schemas << '$IREG_GEN/XMLSchema/SPIRIT/VendorExtensions.xsd'
  181. end
  182. 4 if options[:schema] == '1685-2009' # Magillem tool uses alternate schema
  183. headers = {
  184. 2 'xmlns:spirit' => 'https://www.spiritconsortium.org/XMLSchema/SPIRIT/1685-2009',
  185. 'xmlns:xsi' => 'https://www.w3.org/2001/XMLSchema-instance',
  186. 'xsi:schemaLocation' => schemas.join(' ')
  187. }
  188. else # Assume Spirit 1.4 if not
  189. headers = {
  190. 2 'xmlns:spirit' => 'https://www.spiritconsortium.org/XMLSchema/SPIRIT/1.4',
  191. 'xmlns:xsi' => 'https://www.w3.org/2001/XMLSchema-instance',
  192. 'xsi:schemaLocation' => schemas.join(' ')
  193. }
  194. end
  195. 4 if uvm? && !(options[:schema] == '1685-2009')
  196. 1 headers['xmlns:vendorExtensions'] = '$IREG_GEN/XMLSchema/SPIRIT'
  197. # Else:
  198. # Do nothing ?
  199. # headers['xmlns:vendorExtensions'] = '$UVM_RGM_HOME/builder/ipxact/schema'
  200. end
  201. 4 builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
  202. 4 spirit = xml['spirit']
  203. 4 spirit.component(headers) do
  204. 4 spirit.vendor options[:vendor] || 'Origen'
  205. 4 spirit.library options[:library] || 'Origen'
  206. # I guess this should really be the register owner's owner's name?
  207. 4 spirit.name try(:ip_name) || owner.class.to_s.split('::').last
  208. 4 spirit.version try(:ip_version, :version, :revision)
  209. # The 1685-2009 schema allows for a bus interface. AMBA3 (slave) supported so far.
  210. 4 if options[:schema] == '1685-2009'
  211. 2 if options[:bus_interface] == 'AMBA3'
  212. 1 spirit.busInterfaces do
  213. 1 spirit.busInterface do
  214. 1 spirit.name 'Slave'
  215. bustype_header = {
  216. 1 'spirit:vendor' => options[:vendor] || 'Origen',
  217. 'spirit:library' => 'amba3',
  218. 'spirit:name' => 'APB3',
  219. 'spirit:version' => '1.0'
  220. }
  221. 1 xml['spirit'].busType bustype_header
  222. 1 spirit.slave do
  223. mmapref_header = {
  224. 1 'spirit:memoryMapRef' => options[:mmap_ref] || 'APB'
  225. }
  226. 1 xml['spirit'].memoryMapRef mmapref_header
  227. end
  228. end
  229. end
  230. end
  231. end
  232. 4 spirit.memoryMaps do
  233. 4 memory_maps.each do |map_name, _map|
  234. 4 spirit.memoryMap do
  235. # Optionally assign memory map name to something other than the module name in Ruby,
  236. # default to 'RegisterMap'
  237. 4 spirit.name options[:mmap_name] || 'RegisterMap'
  238. 4 address_blocks do |domain_name, _domain, sub_block|
  239. 10 spirit.addressBlock do
  240. # When registers reside at the top level, do not assign an address block name
  241. 10 if sub_block == owner
  242. 4 if options[:addr_block_name].nil?
  243. 4 spirit.name nil
  244. else
  245. spirit.name options[:addr_block_name]
  246. end
  247. else
  248. 6 spirit.name address_block_name(domain_name, sub_block)
  249. end
  250. 10 spirit.baseAddress sub_block.base_address.to_hex
  251. 10 spirit.range range(sub_block)
  252. 10 spirit.width width(sub_block)
  253. 10 sub_block.regs.each do |name, reg|
  254. # Required for now to ensure that the current value is the reset value
  255. 30 reg.reset
  256. 30 spirit.register do
  257. 30 spirit.name name
  258. 30 spirit.description try(reg, :name_full, :full_name)
  259. 30 spirit.addressOffset reg.offset.to_hex
  260. 30 spirit.size reg.size
  261. 30 if reg.bits.any?(&:writable?)
  262. 26 spirit.access 'read-write'
  263. else
  264. 4 spirit.access 'read-only'
  265. end
  266. 30 spirit.reset do
  267. 30 spirit.value reg.data.to_hex
  268. 30 spirit.mask mask(reg).to_hex
  269. end
  270. 30 reg.named_bits do |name, bits|
  271. 162 spirit.field do
  272. 162 spirit.name name
  273. 162 spirit.description try(bits, :brief_description, :name_full, :full_name)
  274. 162 spirit.bitOffset bits.position
  275. 162 spirit.bitWidth bits.size
  276. # When exporting to 1685-2009 schema, need to handle special cases (writeOnce),
  277. # modifiedWriteValue, and readAction fields.
  278. 162 if options[:schema] == '1685-2009'
  279. 81 if bits.writable? && bits.readable?
  280. 58 if bits.access == :w1
  281. 2 spirit.access 'read-writeOnce'
  282. else
  283. 56 spirit.access 'read-write'
  284. end
  285. 23 elsif bits.writable?
  286. 11 if bits.access == :wo1
  287. 2 spirit.access 'writeOnce'
  288. else
  289. 9 spirit.access 'write-only'
  290. end
  291. 12 elsif bits.readable?
  292. 12 spirit.access 'read-only'
  293. end
  294. 81 if bits.readable?
  295. 70 unless @@access_hash[bits.access][:read].nil?
  296. 22 spirit.readAction @@access_hash[bits.access][:read]
  297. end
  298. end
  299. 81 if bits.writable?
  300. 69 unless @@access_hash[bits.access][:write].nil?
  301. 32 spirit.modifiedWriteValue @@access_hash[bits.access][:write]
  302. end
  303. end
  304. else # Assume Spirit 1.4 if not
  305. 81 spirit.access bits.access
  306. end
  307. # HDL paths provide hooks for a testbench to directly manipulate the
  308. # registers without having to go through a bus interface or read/write
  309. # protocol. Because the hierarchical path to a register block can vary
  310. # greatly between devices, allow the user to provide an abs_path value
  311. # and define "full_reg_path" to assist.
  312. #
  313. # When registers reside at the top level without a specified path, use 'top'.
  314. 162 if reg.owner.path.nil? || reg.owner.path.empty?
  315. 8 regpath = 'top'
  316. else
  317. 154 regpath = reg.owner.path
  318. end
  319. # If :full_reg_path is defined, the :abs_path metadata for a register will
  320. # be used for regpath. This can be assigned at an address block (sub-block)
  321. # level.
  322. 162 unless options[:full_reg_path].nil? == true
  323. regpath = reg.path
  324. end
  325. 162 if options[:schema] == '1685-2009'
  326. 81 spirit.parameters do
  327. 81 spirit.parameter do
  328. 81 spirit.name '_hdlPath_'
  329. # HDL path needs to be to the declared bit field name, NOT to the bus slice
  330. # that Origen's "abs_path" will yield. Ex:
  331. #
  332. # ~~~ ruby
  333. # reg :myreg, 0x0, size: 32 do |reg|
  334. # bits 7..4, :bits_high
  335. # bits 3..0, :bits_low
  336. # end
  337. # ~~~
  338. #
  339. # The abs_path to ...regs(:myreg).bits(:bits_low).abs_path will yield
  340. # "myreg.myreg[3:0]", not "myreg.bits_low". This is not an understood path
  341. # in Origen (myreg[3:0] does not exist in either myreg's RegCollection or BitCollection),
  342. # and does not sync with how RTL would create bits_low[3:0].
  343. # Therefore, use the path to "myreg"'s owner appended with bits.name (bits_low here).
  344. #
  345. # This can be done in a register or sub_blocks definition by defining register
  346. # metadata for "abs_path". If the reg owner's path weren't used, but instead the
  347. # reg's path, that would imply each register was a separate hierarchical path in
  348. # RTL (ex: "top.myblock.regblock.myreg.myreg_bits"), which is normally not the case.
  349. # The most likely path would be "top.myblock.regblock.myreg_bits.
  350. 81 spirit.value "#{regpath}.#{bits.name}"
  351. end
  352. end
  353. end
  354. # C. Hume - Unclear which vendorExtensions should be included by default, if any.
  355. # Future improvment: Allow passing of vendorExtensions enable & value hash/string
  356. # if options[:schema] == '1685-2009'
  357. # spirit.vendorExtensions do
  358. # vendorext = { 'xmlns:vendorExtensions' => '$UVM_RGM_HOME/builder/ipxact/schema' }
  359. # xml['vendorExtensions'].hdl_path vendorext, "#{reg.path}.#{bits.name}"
  360. # end
  361. # end
  362. # Allow optional inclusion of bit field values and descriptions
  363. 162 if options[:include_bit_field_values]
  364. 162 if bits.bit_value_descriptions[0]
  365. 4 bits.bit_value_descriptions.each do |val, desc|
  366. 8 spirit.values do
  367. 8 spirit.value val.to_hex
  368. 8 spirit.name "val_#{val.to_hex}"
  369. 8 spirit.description desc
  370. end
  371. end
  372. end
  373. end
  374. 162 if uvm? && !(options[:schema] == '1685-2009')
  375. 51 spirit.vendorExtensions do
  376. 51 xml['vendorExtensions'].hdl_path "#{regpath}.#{bits.name}"
  377. end
  378. end
  379. end
  380. end
  381. end
  382. end
  383. # Unclear whether addressBlock vendor extensions are supported in Spirit 1.4
  384. # if uvm?
  385. # spirit.vendorExtensions do
  386. # xml['vendorExtensions'].hdl_path sub_block.path(relative_to: owner)
  387. # end
  388. # end
  389. end
  390. end
  391. # Assume byte addressing if not specified
  392. 4 if owner.methods.include?(:lau) == false
  393. 4 if methods.include?(:lau) == true
  394. spirit.addressUnitBits lau
  395. else
  396. 4 spirit.addressUnitBits 8
  397. end
  398. else
  399. spirit.addressUnitBits owner.lau
  400. end
  401. end
  402. end
  403. end
  404. end
  405. end
  406. # When testing with 'origen examples', travis_ci (bash) will end up with empty tags -
  407. # '<spirit:description/>' that do not appear on some user's tshell environments. To
  408. # prevent false errors for this issue, force Nokogiri to use self-closing tags
  409. # ('<spirit:description></spirit:description>'), but keep the XML formatted for readability.
  410. # All tags with no content will appear as '<spirit:tag_name></spirit:tag_name>'.
  411. #
  412. 4 builder.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS |
  413. Nokogiri::XML::Node::SaveOptions::FORMAT)
  414. end
  415. 1 private
  416. 1 def open_memory_map(doc)
  417. 2 maps = doc.xpath('//spirit:memoryMaps/spirit:memoryMap')
  418. 2 maps = [nil] if maps.empty?
  419. 2 maps.each do |mem_map|
  420. 2 yield mem_map
  421. end
  422. end
  423. 1 def reg_description(register)
  424. 4 fetch register.at_xpath('spirit:description'), get_text: true, whitespace: true
  425. end
  426. 1 def bit_description(bit)
  427. 60 desc = fetch(bit.at_xpath('spirit:description'), get_text: true, whitespace: true) || ''
  428. 60 bit_val_present = false
  429. 60 bit.xpath('spirit:values').each do |val|
  430. 4 unless bit_val_present
  431. 2 desc += "\n"
  432. 2 bit_val_present = true
  433. end
  434. 4 value = extract(val, 'spirit:value', format: :integer, hex: true)
  435. 4 value_desc = extract val, 'spirit:description'
  436. 4 if value && value_desc
  437. 4 desc += "\n#{value.to_s(2)} | #{value_desc}"
  438. end
  439. end
  440. 60 desc
  441. end
  442. 1 def mask(reg)
  443. 30 m = 0
  444. 30 reg.size.times do |i|
  445. 464 unless reg[i].reset_val == :undefined
  446. 464 m |= (1 << i)
  447. end
  448. end
  449. 30 m
  450. end
  451. 1 def uvm?
  452. 170 @format == :uvm
  453. end
  454. 1 def memory_maps
  455. 4 { nil => {} }
  456. end
  457. 1 def sub_blocks(domain_name)
  458. 4 owner.all_sub_blocks.select do |sub_block|
  459. 8 sub_block.owns_registers? &&
  460. 6 (sub_block.domains[domain_name] || domain_name == :default)
  461. end
  462. end
  463. 1 def address_blocks
  464. 4 domains = owner.register_domains
  465. 4 domains = { default: {} } if domains.empty?
  466. 4 domains.each do |domain_name, domain|
  467. 4 if owner.owns_registers?
  468. 4 yield domain_name, domain, owner
  469. end
  470. 4 sub_blocks(domain_name).each do |sub_block|
  471. 6 yield domain_name, domain, sub_block
  472. end
  473. end
  474. end
  475. 1 def address_block_name(domain_name, sub_block)
  476. 6 if domain_name == :default
  477. 6 sub_block.name.to_s
  478. else
  479. "#{domain_name}_#{sub_block.name}"
  480. end
  481. end
  482. 1 def width(sub_block)
  483. 20 sub_block.try(:width) || 32
  484. end
  485. 1 def range(sub_block)
  486. 10 range = sub_block.try(:range) || begin
  487. # This is to work around an Origen bug where max_address_reg_size is not updated in the case of
  488. # only one register being present
  489. # TODO: Fix in Origen
  490. 10 max_address_reg_size = sub_block.max_address_reg_size || sub_block.regs.first[1].size
  491. 10 (sub_block.max_reg_address + (max_address_reg_size / 8))
  492. end
  493. 10 width_in_bytes = width(sub_block) / 8
  494. 10 if range % width_in_bytes != 0
  495. 4 range += (width_in_bytes - (range % width_in_bytes))
  496. end
  497. 10 range
  498. end
  499. end
  500. end

lib/cross_origen/ralf.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. 1 module CrossOrigen
  2. 1 class Ralf
  3. # Returns the object that included the CrossOrigen module
  4. 1 attr_reader :owner
  5. 1 def initialize(owner)
  6. 1 @owner = owner
  7. end
  8. # Returns a string representing the owner object in RALF format
  9. 1 def owner_to_ralf(options = {})
  10. 1 Origen.compile("#{Origen.root!}/templates/ralf/default.ralf.erb", options.merge(scope: owner))
  11. end
  12. end
  13. end

lib/cross_origen/xml_doc.rb

84.68% lines covered

111 relevant lines. 94 lines covered and 17 lines missed.
    
  1. 1 require 'kramdown'
  2. 1 require 'sanitize'
  3. 1 module CrossOrigen
  4. # This is the base class of all doc formats that are
  5. # XML based
  6. 1 class XMLDoc
  7. 1 CreationInfo = Struct.new(:author, :date, :revision, :source)
  8. 1 ImportInfo = Struct.new(:name, :date)
  9. 1 attr_accessor :creation_info, :import_info
  10. # These (in many cases illegal) tags will be forced to their valid equivalents
  11. # These will be executed in the defined order, so for later xfrms you can for example
  12. # assume that all 'rows' have already been converted to 'tr'
  13. # valid equivalents
  14. HTML_TRANSFORMS = {
  15. 1 'table/title' => 'caption',
  16. 'table//row' => 'tr',
  17. 'thead//entry' => 'th',
  18. 'table//entry' => 'td',
  19. 'td/p' => 'span',
  20. 'th/p' => 'span'
  21. }
  22. # This can be used to perform additional by-node transformation if required, normally
  23. # this should be used if transform of a node attribute is required
  24. 1 HTML_TRANSFORMER = lambda do |env|
  25. 449 if env[:node_name] == 'td' || env[:node_name] == 'th'
  26. 50 if env[:node].attr('nameend')
  27. 1 first = env[:node].attr('namest').sub('col', '').to_i
  28. 1 last = env[:node].attr('nameend').sub('col', '').to_i
  29. 1 env[:node].set_attribute('colspan', (last - first + 1).to_s)
  30. end
  31. end
  32. end
  33. # Defines the rules for sanitization of any HTML strings that will be converted
  34. # to markdown for representation within Origen
  35. HTML_SANITIZATION_CONFIG = {
  36. # Only these tags will be allowed through, everything else will be stripped
  37. # Note that this is applied after the transforms listed above
  38. 1 elements: %w(b em i strong u p ul ol li table tr td th tbody thead),
  39. attributes: {
  40. 'td' => ['colspan'],
  41. 'th' => ['colspan']
  42. },
  43. # Not planning to allow any of these right now, but keeping around
  44. # as an example of how to do so
  45. #:protocols => {
  46. # 'a' => {'href' => ['http', 'https', 'mailto']}
  47. # }
  48. transformers: HTML_TRANSFORMER
  49. }
  50. # Returns the object that included the CrossOrigen module
  51. 1 attr_reader :owner
  52. 1 def initialize(owner)
  53. 21 @owner = owner
  54. 21 @creation_info = CreationInfo.new
  55. 21 @import_info = ImportInfo.new
  56. end
  57. # Tries the given methods on the owner and returns the first one to return a value,
  58. # ultimately returns nil if no value is found.
  59. #
  60. # To test an object other than the owner pass it as the first argument.
  61. 1 def try(*methods)
  62. 200 if methods.first.is_a?(Symbol)
  63. 8 obj = owner
  64. else
  65. 192 obj = methods.shift
  66. end
  67. 200 methods.each do |method|
  68. 562 if obj.respond_to?(method)
  69. 200 val = obj.send(method)
  70. 200 return val if val
  71. end
  72. end
  73. nil
  74. end
  75. # This returns the doc wrapped by a Nokogiri doc
  76. 1 def doc(path, options = {})
  77. 4 require 'nokogiri'
  78. 4 File.open(path) do |f|
  79. 4 yield Nokogiri::XML(f)
  80. end
  81. end
  82. 1 def extract(element, path, options = {})
  83. options = {
  84. 1154 format: :string,
  85. hex: false,
  86. default: nil,
  87. downcase: false,
  88. return: :text,
  89. # A value or array or values which are considered to be nil, if this is the value
  90. # to be returned then nil will be returned instead
  91. nil_on: false
  92. }.merge(options)
  93. 1154 node = element.at_xpath(path)
  94. 1154 if node
  95. 752 if options[:format] == :string
  96. 586 str = node.send(options[:return]).strip
  97. 586 str = str.downcase if options[:downcase]
  98. 586 if options[:nil_on] && [options[:nil_on]].flatten.include?(str)
  99. nil
  100. else
  101. 586 str
  102. end
  103. 166 elsif options[:format] == :integer
  104. 166 val = node.send(options[:return])
  105. 166 if val =~ /^0x(.*)/
  106. 106 Regexp.last_match[1].to_i(16)
  107. 60 elsif options[:hex]
  108. val.to_i(16)
  109. else
  110. 60 val.to_i(10)
  111. end
  112. else
  113. fail "Unknown format: #{options[:format]}"
  114. end
  115. else
  116. 402 options[:default]
  117. end
  118. end
  119. # Freescale register descriptions are like the wild west, need to do some pre-screening
  120. # to approach valid HTML before handing off to other off the shelf sanitizers
  121. 1 def pre_sanitize(html)
  122. 4 html = Nokogiri::HTML.fragment(html)
  123. 4 HTML_TRANSFORMS.each do |orig, new|
  124. 108 html.xpath(".//#{orig}").each { |node| node.name = new }
  125. end
  126. 4 html.to_html
  127. end
  128. # Does its best to convert the given html fragment to markdown
  129. #
  130. # The final markdown may still contain some HTML tags, but any weird
  131. # markup which may break a future markdown -> html conversion will
  132. # be removed
  133. 1 def to_markdown(html, _options = {})
  134. 4 cleaned = html.scrub
  135. 4 cleaned = pre_sanitize(cleaned)
  136. 4 cleaned = Sanitize.fragment(cleaned, HTML_SANITIZATION_CONFIG)
  137. 4 Kramdown::Document.new(cleaned, input: :html).to_kramdown.strip
  138. rescue
  139. 'The description could not be imported, the most likely cause of this is that it contained illegal HTML markup'
  140. end
  141. # Convert the given markdown string to HTML
  142. 1 def to_html(string, _options = {})
  143. # Escape any " that are not already escaped
  144. 2 string.gsub!(/([^\\])"/, '\1\"')
  145. # Escape any ' that are not already escaped
  146. 2 string.gsub!(/([^\\])'/, %q(\1\\\'))
  147. 2 html = Kramdown::Document.new(string, input: :kramdown).to_html
  148. end
  149. # fetch an XML snippet passed and extract and format the data
  150. 1 def fetch(xml, options = {})
  151. options = {
  152. 426 type: String,
  153. downcase: false,
  154. symbolize: false,
  155. strip: false,
  156. squeeze: false,
  157. squeeze_lines: false,
  158. rm_specials: false,
  159. whitespace: false,
  160. get_text: false,
  161. to_i: false,
  162. to_html: false,
  163. to_bool: false,
  164. children: false,
  165. to_dec: false,
  166. to_f: false,
  167. underscore: false
  168. }.update(options)
  169. 426 options[:symbolize] = options[:to_sym] if options[:to_sym]
  170. # Check for incompatible options
  171. 426 xml_orig = xml
  172. 426 numeric_methods = [:to_i, :to_f, :to_dec]
  173. 426 if options[:get_text] == true && options[:to_html] == true
  174. fail 'Cannot use :get_text and :to_html options at the same time, exiting...'
  175. end
  176. 426 if options[:symbolize] == true
  177. 272 fail 'Cannot convert to a number of any type and symbolize at the same time' if numeric_methods.reject { |arg| options[arg] == true }.size < 3
  178. end
  179. 1704 fail 'Cannot select multiple numeric conversion args at the same time' if numeric_methods.reject { |arg| options[arg] == true }.size < 2
  180. 426 if xml.nil?
  181. 33 Origen.log.debug 'XML data is nil!'
  182. 33 return nil
  183. end
  184. 393 xml = xml.text if options[:get_text] == true
  185. # Sometimes XML snippets get sent as nodes or as Strings
  186. # Must skip this code if a String as it is designed to change
  187. # the XML node into a string
  188. 393 unless xml.is_a? String
  189. if options[:to_html] == true
  190. if xml.children
  191. # If there are children to this XMl node then grab the content there
  192. if xml.children.empty? || options[:children] == false
  193. xml = xml.to_html
  194. else
  195. xml = xml.children.to_html
  196. end
  197. end
  198. end
  199. end
  200. 393 unless xml.is_a? options[:type]
  201. Origen.log.debug "XML data is not of correct type '#{options[:type]}'"
  202. Origen.log.debug "xml is \n#{xml}"
  203. return nil
  204. end
  205. 393 if options[:type] == String
  206. 393 if xml.match(/\s+/) && options[:whitespace] == false
  207. Origen.log.debug "XML data '#{xml}' cannot have white space"
  208. return nil
  209. end
  210. 393 xml.downcase! if options[:downcase] == true
  211. 393 xml = xml.underscore if options[:underscore] == true
  212. 393 xml.strip! if options[:strip] == true
  213. 393 xml.squeeze!(' ') if options[:squeeze] == true
  214. 393 xml = xml.squeeze_lines if options[:squeeze_lines] == true
  215. 393 xml.gsub!(/[^0-9A-Za-z]/, '_') if options[:rm_specials] == true
  216. 393 if options[:symbolize] == true
  217. 68 return xml.to_sym
  218. 325 elsif options[:to_i] == true
  219. 126 return xml.to_i
  220. 199 elsif options[:to_dec] == true
  221. 16 return xml.to_dec
  222. 183 elsif options[:to_f] == true
  223. return xml.to_f
  224. 183 elsif [true, false].include?(xml.to_bool) && options[:to_bool] == true
  225. # If the string can convert to Boolean then return TrueClass or FalseClass
  226. return xml.to_bool
  227. else
  228. 183 return xml
  229. end
  230. else
  231. # No real examples yet of non-string content
  232. return xml
  233. end
  234. end
  235. end
  236. end

lib/cross_origen_dev/dut.rb

100.0% lines covered

64 relevant lines. 64 lines covered and 0 lines missed.
    
  1. 1 module CrossOrigenDev
  2. # Simple DUT class used for testing
  3. 1 class DUT
  4. 1 include Origen::TopLevel
  5. 1 include CrossOrigen
  6. 1 def initialize
  7. 15 @path = :hidden
  8. 15 sub_block :atx, class_name: 'D_IP_ANA_TEST_ANNEX_SYN', base_address: 0x4000_0000
  9. # Register defined solely to test out the top level register export
  10. 15 reg :dut_top_level_reg, 0x0, size: 32, bit_order: :msb0, lau: 8 do
  11. 15 bit 15, :pls_work, reset: 1, access: :rw
  12. 15 bit 14, :second_bit, reset: 0, access: :rw
  13. end
  14. # Register defined solely to test out the top level register export
  15. 15 reg :dut_top_level_reg_number_two, 0x10, size: 32, bit_order: :lsb0, lau: 16 do
  16. 15 bit 0, :pls_work, reset: 0, access: :ro
  17. 15 bit 1, :second_bit, reset: 1, access: :rw
  18. end
  19. # Import some data from IP-XACT
  20. 15 cr_import(path: "#{Origen.root}/imports/ipxact.xml")
  21. end
  22. # Import Spirit 1.4 version of ATX
  23. 1 def add_atx2
  24. 1 sub_block :atx2, class_name: 'ATX2', base_address: 0x6000_0000
  25. end
  26. 1 class ATX2
  27. 1 include Origen::Model
  28. 1 include CrossOrigen
  29. 1 def initialize
  30. 1 cr_import(path: "#{Origen.root}/approved/ip_xact_sub_block.xml", refresh: true)
  31. end
  32. end
  33. # Import 1685-2009 version of ATX
  34. 1 def add_atx3
  35. 1 sub_block :atx3, class_name: 'ATX3', base_address: 0x7000_0000
  36. end
  37. 1 class ATX3
  38. 1 include Origen::Model
  39. 1 include CrossOrigen
  40. 1 def initialize
  41. 1 cr_import(path: "#{Origen.root}/approved/ip_xact_sub_block_1685.xml", refresh: true)
  42. end
  43. end
  44. 1 class D_IP_ANA_TEST_ANNEX_SYN # rubocop:disable ClassAndModuleCamelCase
  45. 1 include Origen::Model
  46. 1 include CrossOrigen
  47. 1 def initialize
  48. # A manually defined set of registers for testing the conversion of any specific attributes
  49. # ** MPU Clock Divider Register **
  50. #
  51. # The MCLKDIV register is used to divide down the frequency of the OSCCLK input. If the MCLKDIV
  52. # register is set to value "N", then the output (beat) frequency of the clock divider is OSCCLK / (N+1). The
  53. # resulting beats are, in turn, counted by the TIMER module to control the duration of operations.
  54. # This is a test of potentially problematic characters ' " \' \" < >
  55. 15 reg :mclkdiv, 0x0, size: 16, bit_order: 'decrement' do
  56. # **Oscillator (Hi)** - Clock source selection. (Note that in addition to this firmware-controlled bit, the
  57. # clock source is also dependent on test and power control discretes).
  58. #
  59. # 0 | Clock is the externally supplied bus clock bus_clk
  60. # 1 | Clock is the internal oscillator from the hardblock
  61. 15 bit 15, :osch, reset: 1, access: :rw
  62. # **Divider Value**
  63. #
  64. # Used to set clock divider value and test multi-bit import in CrossOrigen
  65. 15 bits 3..0, :div
  66. end
  67. # **Access Type Test Register**
  68. #
  69. # This register tests the IP-XACT export of various bit access types, such as write-one-to-clear,
  70. # read-only, etc.
  71. 15 reg :access_types, 0x4, size: 32 do
  72. # Test read-only access.
  73. 15 bit 31, :readonly, access: :ro
  74. # Test read-write access.
  75. 15 bit 30, :readwrite, access: :rw
  76. # Test read-clear access, where a read clears the value afterwards.
  77. 15 bit 29, :readclear, access: :rc
  78. # Test read-set access, where a read sets the bit afterwards.
  79. 15 bit 28, :readset, access: :rs
  80. # Test writable, clear-on-read access, etc...
  81. 15 bit 27, :writablereadclear, access: :wrc
  82. 15 bit 26, :writablereadset, access: :wrs
  83. 15 bit 25, :writeclear, access: :wc
  84. 15 bit 24, :writeset, access: :ws
  85. 15 bit 23, :writesetreadclear, access: :wsrc
  86. 15 bit 22, :writeclearreadset, access: :wcrs
  87. 15 bit 21, :write1toclear, access: :w1c
  88. 15 bit 20, :write1toset, access: :w1s
  89. 15 bit 19, :write1totoggle, access: :w1t
  90. 15 bit 18, :write0toclear, access: :w0c
  91. 15 bit 17, :write0toset, access: :w0s
  92. 15 bit 16, :write0totoggle, access: :w0t
  93. 15 bit 15, :write1tosetreadclear, access: :w1src
  94. 15 bit 14, :write1toclearreadset, access: :w1crs
  95. 15 bit 13, :write0tosetreadclear, access: :w0src
  96. 15 bit 12, :write0toclearreadset, access: :w0crs
  97. 15 bit 11, :writeonly, access: :wo
  98. 15 bit 10, :writeonlyclear, access: :woc
  99. 15 bit 9, :writeonlyreadzero, access: :worz
  100. 15 bit 8, :writeonlyset, access: :wos
  101. 15 bit 7, :writeonce, access: :w1
  102. 15 bit 6, :writeonlyonce, access: :wo1
  103. 15 bit 5, :readwritenocheck, access: :dc
  104. 15 bit 4, :readonlyclearafter, access: :rowz
  105. end
  106. end
  107. end
  108. end
  109. end