Class: CrossOrigen::CMSISSVD

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

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

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

Constructor Details

This class inherits a constructor from CrossOrigen::XMLDoc

Instance Method Details

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

rubocop:disable CyclomaticComplexity



3
4
5
6
7
8
9
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/cross_origen/cmsis_svd.rb', line 3

def import(file, options = {}) # rubocop:disable CyclomaticComplexity
  with_output_file(options) do |f|
    doc(file, options) do |doc|
      f.puts '# This file was automatically generated from a CMSIS-SVD input file'
      f.puts '# Name:    ' + (fetch(doc.xpath('device/name'), get_text: true) || '')
      f.puts '# Version: ' + (fetch(doc.xpath('device/version'), get_text: true) || '')
      f.puts "# Created at #{Time.now.strftime('%e %b %Y %H:%M%p')} by #{User.current.name}"
      f.puts '# rubocop:disable all'
      f.puts 'module ImportedCMSISSVD'
      f.puts '  def initialize(*args)'
      f.puts '    instantiate_imported_cmsis_svd_data'
      f.puts '  end'
      f.puts ''
      f.puts '  def instantiate_imported_cmsis_svd_data'

      # Create sub-blocks
      indexes = {}
      doc.xpath('device/peripherals/peripheral').each do |p|
        name = fetch(p.xpath('groupName'), get_text: true)
        name = name.to_s.downcase.symbolize
        ba = extract(p, 'baseAddress', format: :integer, hex: true)
        if j = peripheral_groups(doc)[name] > 1
          indexes[name] ||= 0
          f.puts "    sub_block :#{name}#{indexes[name]}, base_address: #{ba.to_hex}"
          indexes[name] += 1
        else
          f.puts "    sub_block :#{name}, base_address: #{ba.to_hex}"
        end
      end
      f.puts ''

      # Add registers to each sub-block
      indexes = {}
      doc.xpath('device/peripherals/peripheral').each do |p|
        sb = fetch(p.xpath('groupName'), get_text: true)
        sb = sb.to_s.downcase.symbolize
        if j = peripheral_groups(doc)[sb] > 1
          indexes[sb] ||= 0
          ix = indexes[sb]
          indexes[sb] += 1
          sb = "#{sb}#{ix}"
        end

        p.xpath('registers/register').each do |r|
          name = extract(r, 'name')
          di = extract(r, 'dim', format: :integer)
          dim = !!di
          if dim
            dinc = extract(r, 'dimIncrement', format: :integer)
            dvals = extract(r, 'dimIndex').split(',')
          else
            di = 1
          end
          offset = extract(r, 'addressOffset', format: :integer, hex: true)
          size = extract(r, 'size', format: :integer)
          reset = extract(r, 'resetValue', format: :integer, hex: true)
          desc = (extract(r, 'description') || '').gsub("'", %q(\\\'))

          di.times do |i|
            if dim
              n = name.sub('[%s]', dvals[i])
              addr = offset + (i * dinc)
            else
              n = name
              addr = offset
            end
            f.puts "    #{sb}.add_reg :#{n.downcase.symbolize}, #{addr.to_hex}, size: #{size}#{reset ? ', reset: ' + reset.to_hex : ''}, description: '#{desc}' do |reg|"
            r.xpath('fields/field').each do |b|
              bn = extract(b, 'name')
              unless bn == 'RESERVED'
                bn = bn.to_s.downcase.symbolize
                lsb = extract(b, 'lsb', format: :integer)
                msb = extract(b, 'msb', format: :integer)
                access = extract(b, 'access')
                desc = (extract(r, 'description') || '').gsub("'", %q(\\\'))
                case access
                when 'read-only'
                  ac = :ro
                else
                  ac = :rw
                end
                if lsb == msb
                  f.puts "      reg.bit #{lsb}, :#{bn}, access: :#{ac}, description: '#{desc}'"
                else
                  f.puts "      reg.bit #{msb}..#{lsb}, :#{bn}, access: :#{ac}, description: '#{desc}'"
                end
              end
            end
            f.puts '    end'
          end
        end
      end

      f.puts '  end'

      # Create accessor methods to return an array of peripherals in the case
      # where there are many in a group
      peripheral_groups(doc).each do |name, size|
        name = name.to_s.downcase.symbolize
        if size > 1
          f.puts ''
          f.puts "  def #{name}"
          f.print '    ['
          size.times do |i|
            if i == 0
              f.print "#{name}0"
            else
              f.print ", #{name}#{i}"
            end
          end
          f.puts ']'
          f.puts '  end'
        end
      end

      f.puts 'end'
      f.puts '# rubocop:enable all'
    end
  end
end

#peripheral_groups(doc) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/cross_origen/cmsis_svd.rb', line 124

def peripheral_groups(doc)
  @peripheral_groups ||= begin
    g = {}
    doc.xpath('device/peripherals/peripheral').each do |p|
      group = fetch(p.xpath('groupName'), get_text: true)
      group = group.to_s.downcase.symbolize
      g[group] ||= 0
      g[group] += 1
    end
    g
  end
end

#with_output_file(options = {}) ⇒ Object



137
138
139
140
141
# File 'lib/cross_origen/cmsis_svd.rb', line 137

def with_output_file(options = {})
  path = options[:output] || 'imported_cmsis_svd.rb'
  File.open(path, 'w') { |f| yield f }
  puts "Successfully imported to #{path}"
end