cross_origen 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/config/application.rb +78 -0
- data/config/commands.rb +47 -0
- data/config/development.rb +17 -0
- data/config/environment.rb +35 -0
- data/config/users.rb +18 -0
- data/config/version.rb +8 -0
- data/lib/cross_origen/design_sync.rb +54 -0
- data/lib/cross_origen/headers.rb +21 -0
- data/lib/cross_origen/ip_xact.rb +243 -0
- data/lib/cross_origen/origen_format.rb +541 -0
- data/lib/cross_origen/ralf.rb +15 -0
- data/lib/cross_origen/test/dut.rb +51 -0
- data/lib/cross_origen/xml_doc.rb +252 -0
- data/lib/cross_origen.rb +108 -0
- data/templates/headers/default.h.erb +18 -0
- data/templates/ralf/_register.ralf.erb +21 -0
- data/templates/ralf/default.ralf.erb +37 -0
- data/templates/test/default.ralf.erb +1 -0
- data/templates/test/headers_default.h.erb +1 -0
- data/templates/test/ip_xact.xml.erb +1 -0
- data/templates/web/_history.md +547 -0
- data/templates/web/example.md.erb +73 -0
- data/templates/web/examples/ip_xact_export.md.erb +25 -0
- data/templates/web/examples/origen_export.md.erb +96 -0
- data/templates/web/examples/ralf_export.md.erb +18 -0
- data/templates/web/examples.md.erb +13 -0
- data/templates/web/index.md.erb +104 -0
- data/templates/web/layouts/_basic.html.erb +13 -0
- data/templates/web/layouts/_doc.html.erb +61 -0
- data/templates/web/partials/_navbar.html.erb +23 -0
- data/templates/web/release_notes.md.erb +5 -0
- metadata +117 -0
@@ -0,0 +1,541 @@
|
|
1
|
+
module CrossOrigen
|
2
|
+
class OrigenFormat
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
SUB_BLOCK_ATTRS = {
|
6
|
+
base_address: 'IP base address',
|
7
|
+
byte_order: 'Describes endianness of the IP. Values possible are :big_endian and :little_endian',
|
8
|
+
lau: 'IP Least Addressable Unit: Values possible are (1..32)',
|
9
|
+
version: 'IP version',
|
10
|
+
instance: 'IP instance',
|
11
|
+
instance_module: 'IP module',
|
12
|
+
class_name: 'Class name',
|
13
|
+
instance: 'IP instance',
|
14
|
+
instance_module: 'IP module',
|
15
|
+
addr_block_name: 'Address block name',
|
16
|
+
space: 'Address block space'
|
17
|
+
}
|
18
|
+
|
19
|
+
FILE_COMMENTS = {
|
20
|
+
class: "\# This file is created by Origen via CrossOrigen::OrigenFormat#export, and is read-only.\n\# If you need to make changes, re-open the class\n",
|
21
|
+
incl: "\# This file is created by Origen via CrossOrigen::OrigenFormat#export, and is read-only"
|
22
|
+
}
|
23
|
+
|
24
|
+
attr_reader :obj, :top_level_class, :top_level_hierarchy, :output_dir, :top_level_path, :incl_path, :incl_dir, :file_content
|
25
|
+
|
26
|
+
def initialize(options = {})
|
27
|
+
options = {
|
28
|
+
obj: $dut,
|
29
|
+
path: "#{Origen.root!}/output"
|
30
|
+
}.update(options)
|
31
|
+
@obj = options[:obj]
|
32
|
+
@output_dir = options[:path]
|
33
|
+
@top_level_path = "#{output_dir}/top_level.rb"
|
34
|
+
@incl_path = "#{output_dir}/sub_blocks.rb"
|
35
|
+
@incl_dir = "#{output_dir}/import"
|
36
|
+
@top_level_hierarchy = get_namespace(options)
|
37
|
+
@top_level_class = @top_level_hierarchy.keys.last
|
38
|
+
|
39
|
+
# first key is file type (:bom or :incl) and second is object name
|
40
|
+
@file_content = Hash.new do |h, k|
|
41
|
+
h[k] = {}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def export
|
46
|
+
# Delete any previous files
|
47
|
+
FileUtils.rm_rf(@incl_dir) if File.exist?(@incl_dir)
|
48
|
+
FileUtils.mkdir_p(@incl_dir)
|
49
|
+
|
50
|
+
# Check if previous version of top-level files exist and delete them
|
51
|
+
File.delete(@top_level_path) if File.exist?(@top_level_path)
|
52
|
+
File.delete(@incl_path) if File.exist?(@incl_path)
|
53
|
+
|
54
|
+
# Create the sub_block objects in the top_level.rb file
|
55
|
+
# This method will create each required class file recursively (indirectly)
|
56
|
+
# and will gather all of the information required to create the include file.
|
57
|
+
# In essence it does it all
|
58
|
+
create_bom
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# Creates the BoM file that creates the sub_blocks from the meta-modelled sub_blocks
|
64
|
+
def create_bom
|
65
|
+
indent = ''
|
66
|
+
file_content = {}
|
67
|
+
full_class = @top_level_hierarchy.keys.last
|
68
|
+
klass = @top_level_class.demodulize
|
69
|
+
Origen.log.info 'Exporting to Origen format...'
|
70
|
+
File.open(@top_level_path, 'w') do |bom_file|
|
71
|
+
# bom_file.chmod(0555)
|
72
|
+
bom_file.puts(FILE_COMMENTS[:incl])
|
73
|
+
bom_file.puts("require_relative 'sub_blocks'")
|
74
|
+
@top_level_hierarchy.each do |name, obj|
|
75
|
+
bom_file.puts("#{indent}#{obj} #{name.split('::').last}")
|
76
|
+
indent += ' '
|
77
|
+
end
|
78
|
+
bom_file.puts("#{indent}include Origen::Model")
|
79
|
+
bom_file.puts('')
|
80
|
+
bom_file.puts("#{indent}def initialize(options = {})")
|
81
|
+
indent += ' '
|
82
|
+
# This method is recursive (indirectly) so file_content should find all BoM and include file strings
|
83
|
+
create_file_content(@obj, indent)
|
84
|
+
@file_content.each do |file_type, str_hash|
|
85
|
+
if file_type == :bom
|
86
|
+
str_hash.each do |_obj, str|
|
87
|
+
bom_file.puts(str)
|
88
|
+
end
|
89
|
+
elsif file_type == :incl
|
90
|
+
# Create the include file
|
91
|
+
File.open(@incl_path, 'w') do |incl_file|
|
92
|
+
str_hash.each do |_obj, str|
|
93
|
+
incl_file.puts(str)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
else
|
97
|
+
Origen.log.error 'Incorrect key for @file_content instance variable Hash, must be :incl or :bom'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if @obj.owns_registers?
|
101
|
+
@obj.regs.each do |_reg_name, r|
|
102
|
+
reg_path = r.path.gsub(/#{klass}./i, '')
|
103
|
+
reg_path.chop! if reg_path[-1] == '.'
|
104
|
+
r.description.each do |line|
|
105
|
+
bom_file.puts("#{indent}# #{line}")
|
106
|
+
end
|
107
|
+
reg_string = "#{indent}reg :#{r.name}, #{r.address.to_hex}, size: #{r.size}"
|
108
|
+
if r.respond_to? :bit_order
|
109
|
+
if r.bit_order.is_a?(String)
|
110
|
+
reg_string += ", bit_order: '#{r.bit_order}'"
|
111
|
+
elsif r.bit_order.is_a?(Symbol)
|
112
|
+
reg_string += ", bit_order: :#{r.bit_order}"
|
113
|
+
elsif r.bit_order.is_a?(NilClass)
|
114
|
+
# do not add bitorder if it is not available
|
115
|
+
else
|
116
|
+
reg_string += ", bit_order: #{r.bit_order}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
if r.respond_to? :space
|
120
|
+
if r.space.is_a?(String)
|
121
|
+
reg_string += ", space: '#{r.space}'"
|
122
|
+
elsif r.space.is_a?(Symbol)
|
123
|
+
reg_string += ", space: :#{r.space}"
|
124
|
+
else
|
125
|
+
reg_string += ", space: #{r.space}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
bom_file.puts("#{reg_string} do |reg|")
|
129
|
+
indent += ' '
|
130
|
+
r.named_bits do |field, bits|
|
131
|
+
if bits.size > 1
|
132
|
+
bit_index = "#{bits.position}..#{bits.position + bits.size - 1}"
|
133
|
+
else
|
134
|
+
bit_index = bits.position.to_s
|
135
|
+
end
|
136
|
+
bits.description.each do |line|
|
137
|
+
bom_file.puts("#{indent}# #{line}")
|
138
|
+
end
|
139
|
+
bom_file.puts("#{indent}reg.bit #{bit_index}, :#{field}, reset: 0b#{bits.reset_val.to_s(2)}, access: :#{bits.access}")
|
140
|
+
end
|
141
|
+
indent = indent[0..-3]
|
142
|
+
bom_file.puts("#{indent}end")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
indent = indent[0..-3]
|
146
|
+
bom_file.puts("#{indent}end")
|
147
|
+
@top_level_hierarchy.each do |_name, _obj|
|
148
|
+
indent = indent[0..-3]
|
149
|
+
bom_file.puts("#{indent}end")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
# Give a newline on console to sepearate out the '.' used for progress indicator
|
153
|
+
puts
|
154
|
+
end
|
155
|
+
|
156
|
+
# Create the bom string for the current object. Recursive method until no more sub_blocks are found for the current object
|
157
|
+
def create_file_content(obj, indent)
|
158
|
+
unless obj.respond_to?(:sub_blocks) && obj.send(:sub_blocks)
|
159
|
+
Origen.log.warn 'Object argument does not have sub_blocks, ignoring it...'
|
160
|
+
return
|
161
|
+
end
|
162
|
+
obj.sub_blocks.each do |name, sb|
|
163
|
+
@file_content[:bom][name] = "#{indent}sub_block :#{name}"
|
164
|
+
instance_vars_with_content(sb).each do |attr, value|
|
165
|
+
if value.is_a?(String)
|
166
|
+
@file_content[:bom][name] += ", #{attr}: '#{value}'"
|
167
|
+
elsif value.is_a?(Symbol)
|
168
|
+
@file_content[:bom][name] += ", #{attr} = :#{value}"
|
169
|
+
else
|
170
|
+
if attr == :base_address
|
171
|
+
@file_content[:bom][name] += ", #{attr}: #{value.to_hex}"
|
172
|
+
else
|
173
|
+
@file_content[:bom][name] += ", #{attr}: #{value}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
@file_content[:bom][name] += ", abs_path: '#{sb.path}'"
|
178
|
+
# Add on the class_name attr as this is not part of the sub_block meta_model
|
179
|
+
class_name = sb.class.to_s.demodulize
|
180
|
+
if class_name == 'SubBlock'
|
181
|
+
file_content[:bom][name] += ", class_name: '#{sb.name.upcase}'"
|
182
|
+
else
|
183
|
+
file_content[:bom][name] += ", class_name: '#{class_name}'"
|
184
|
+
end
|
185
|
+
# Create the class file for this object
|
186
|
+
create_class_file(sb)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def create_class_file(obj)
|
191
|
+
ivars_content = {}
|
192
|
+
ivars_content = instance_vars_with_content(obj)
|
193
|
+
indent = ''
|
194
|
+
klass = get_full_class(obj)
|
195
|
+
class_path_addition = (klass.split('::') - @top_level_class.split('::')).join('/').downcase
|
196
|
+
@file_content[:incl][klass] = "require_relative 'import/#{class_path_addition}'"
|
197
|
+
class_file_name = Pathname.new("#{@incl_dir}/#{class_path_addition}.rb")
|
198
|
+
class_file_dir = class_file_name.dirname
|
199
|
+
unless class_file_dir.exist?
|
200
|
+
Origen.log.debug "app: Directory #{class_file_dir} does not exist, creating it..."
|
201
|
+
FileUtils.mkdir_p(class_file_dir)
|
202
|
+
end
|
203
|
+
File.open(class_file_name, 'w') do |file|
|
204
|
+
# file.chmod(0555)
|
205
|
+
file.puts('# -*- encoding : utf-8 -*-') if RUBY_VERSION < '2.0.0'
|
206
|
+
file.puts(FILE_COMMENTS[:class])
|
207
|
+
# print out the top level object hierarchy
|
208
|
+
@top_level_hierarchy.each do |name, o|
|
209
|
+
file.puts("#{indent}#{o} #{name.split('::').last}")
|
210
|
+
indent += ' '
|
211
|
+
end
|
212
|
+
# print out the current object's sub-hierarchy
|
213
|
+
sub_array = klass.split('::') - @top_level_class.split('::')
|
214
|
+
object_type_array = %w(class) * sub_array.size
|
215
|
+
sub_hierarchy = Hash[sub_array.zip object_type_array]
|
216
|
+
sub_hierarchy.each do |name, o|
|
217
|
+
if o == sub_hierarchy.values.last
|
218
|
+
file.puts("#{indent}#{o} #{name.split('::').last} # rubocop:disable ClassLength")
|
219
|
+
else
|
220
|
+
file.puts("#{indent}#{o} #{name.split('::').last}")
|
221
|
+
end
|
222
|
+
indent += ' '
|
223
|
+
end
|
224
|
+
file.puts("#{indent}include Origen::Model")
|
225
|
+
file.puts('')
|
226
|
+
instance_vars_with_content(obj).each do |attr, _value|
|
227
|
+
file.puts("#{indent}# #{SUB_BLOCK_ATTRS[attr]}")
|
228
|
+
file.puts("#{indent}attr_reader :#{attr}")
|
229
|
+
file.puts('')
|
230
|
+
end
|
231
|
+
file.puts("#{indent}def initialize(options = {})")
|
232
|
+
indent += ' '
|
233
|
+
instance_vars_with_content(obj).each do |attr, value|
|
234
|
+
if value.is_a?(String)
|
235
|
+
file.puts("#{indent}\@#{attr} = '#{value}'")
|
236
|
+
elsif value.is_a?(Symbol)
|
237
|
+
file.puts("#{indent}\@#{attr} = :#{value}")
|
238
|
+
else
|
239
|
+
if attr == :base_address
|
240
|
+
file.puts("#{indent}\@#{attr} = #{value.to_hex}")
|
241
|
+
else
|
242
|
+
file.puts("#{indent}\@#{attr} = #{value}")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
# If the current object has sub_block they need to be instantiated in the init
|
247
|
+
if obj.respond_to?(:sub_blocks)
|
248
|
+
obj.sub_blocks.each do |n, block|
|
249
|
+
bom_string = "#{indent}sub_block :#{n}"
|
250
|
+
instance_vars_with_content(block).each do |attr, value|
|
251
|
+
if value.is_a?(String)
|
252
|
+
bom_string += ", #{attr}: '#{value}'"
|
253
|
+
elsif value.is_a?(Symbol)
|
254
|
+
bom_string += ", #{attr}: :#{value}"
|
255
|
+
else
|
256
|
+
if attr == :base_address
|
257
|
+
bom_string += ", #{attr}: #{value.to_hex}"
|
258
|
+
else
|
259
|
+
bom_string += ", #{attr}: #{value}"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
bom_string += ", abs_path: '#{block.path}'"
|
264
|
+
# Add on the class_name attr as this is not part of the sub_block meta_model
|
265
|
+
class_name = block.class.to_s.split('::').last
|
266
|
+
if class_name == 'SubBlock'
|
267
|
+
bom_string += ", class_name: '#{block.name.upcase}'"
|
268
|
+
else
|
269
|
+
bom_string += ", class_name: '#{class_name}'"
|
270
|
+
end
|
271
|
+
file.puts(bom_string)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
file.puts("#{indent}instantiate_registers(options)") if obj.owns_registers?
|
275
|
+
indent = indent[0..-3]
|
276
|
+
file.puts("#{indent}end")
|
277
|
+
if obj.owns_registers?
|
278
|
+
file.puts('')
|
279
|
+
file.puts("#{indent}# rubocop:disable LineLength")
|
280
|
+
# Need the register and bit_field descriptions to use double quotes
|
281
|
+
file.puts("#{indent}# rubocop:disable StringLiterals")
|
282
|
+
file.puts("#{indent}def instantiate_registers(options = {}) # rubocop:disable MethodLength")
|
283
|
+
indent += ' '
|
284
|
+
obj.regs.each do |_reg_name, r|
|
285
|
+
reg_addr_offset = (r.address - obj.base_address).to_hex
|
286
|
+
reg_path = r.path.gsub(/#{klass}./i, '')
|
287
|
+
reg_path.chop! if reg_path[-1] == '.'
|
288
|
+
r.description.each do |line|
|
289
|
+
file.puts("#{indent}# #{line}")
|
290
|
+
end
|
291
|
+
reg_string = "#{indent}reg :#{r.name}, #{reg_addr_offset}, size: #{r.size}"
|
292
|
+
if r.respond_to? :bit_order
|
293
|
+
if r.bit_order.is_a?(String)
|
294
|
+
reg_string += ", bit_order: '#{r.bit_order}'"
|
295
|
+
elsif r.bit_order.is_a?(Symbol)
|
296
|
+
reg_string += ", bit_order: :#{r.bit_order}"
|
297
|
+
elsif r.bit_order.is_a?(NilClass)
|
298
|
+
# do not add bitorder if it is not available
|
299
|
+
else
|
300
|
+
reg_string += ", bit_order: #{r.bit_order}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
if r.respond_to? :space
|
304
|
+
if r.space.is_a?(String)
|
305
|
+
reg_string += ", space: '#{r.space}'"
|
306
|
+
elsif r.space.is_a?(Symbol)
|
307
|
+
reg_string += ", space: :#{r.space}"
|
308
|
+
else
|
309
|
+
reg_string += ", space: #{r.space}"
|
310
|
+
end
|
311
|
+
end
|
312
|
+
file.puts("#{reg_string} do |reg|")
|
313
|
+
indent += ' '
|
314
|
+
r.named_bits do |field, bits|
|
315
|
+
plain_bit_description = Nokogiri::HTML(bits.description.join(' ').to_s).text
|
316
|
+
plain_bit_description.gsub!(/"/, "'")
|
317
|
+
if bits.size > 1
|
318
|
+
bit_index = "#{bits.position + bits.size - 1}..#{bits.position}"
|
319
|
+
else
|
320
|
+
bit_index = bits.position.to_s
|
321
|
+
end
|
322
|
+
bits.description.each do |line|
|
323
|
+
file.puts("#{indent}# #{line}")
|
324
|
+
end
|
325
|
+
file.puts("#{indent}reg.bit #{bit_index}, :#{field}, reset: 0b#{bits.reset_val.to_s(2)}, access: :#{bits.access}")
|
326
|
+
end
|
327
|
+
indent = indent[0..-3]
|
328
|
+
file.puts("#{indent}end")
|
329
|
+
end
|
330
|
+
indent = indent[0..-3]
|
331
|
+
file.puts("#{indent}end")
|
332
|
+
end
|
333
|
+
@top_level_hierarchy.each do |_name, _obj|
|
334
|
+
indent = indent[0..-3]
|
335
|
+
file.puts("#{indent}end")
|
336
|
+
end
|
337
|
+
sub_hierarchy.each do |_name, _obj|
|
338
|
+
indent = indent[0..-3]
|
339
|
+
file.puts("#{indent}end")
|
340
|
+
end
|
341
|
+
end
|
342
|
+
# Place a '.' to the console to indicate file write progress to the user
|
343
|
+
print '.'
|
344
|
+
# If the current obj has sub_blocks then write those class files
|
345
|
+
if obj.respond_to?(:sub_blocks) && obj.send(:sub_blocks)
|
346
|
+
obj.sub_blocks.each do |_name, sb|
|
347
|
+
create_class_file(sb)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
# Creates the class files for the sub_blocks instantiated in the BoM
|
353
|
+
def create_class_files
|
354
|
+
indent = ''
|
355
|
+
object_hierarchy = get_namespace(@obj)
|
356
|
+
klass = @obj.class.to_s.split('::').last
|
357
|
+
File.open(@incl_path, 'w') do |incl_file|
|
358
|
+
incl_file.chmod(0555)
|
359
|
+
incl_file.puts(FILE_COMMENTS[:incl])
|
360
|
+
@obj.sub_blocks.each do |_name, sb|
|
361
|
+
current_bist = nil
|
362
|
+
bypass_addr = 0
|
363
|
+
incl_file.puts("require_relative 'import/#{sb.name}.rb'")
|
364
|
+
File.open("#{@incl_dir}/#{sb.name}.rb", 'w') do |file|
|
365
|
+
file.chmod(0555)
|
366
|
+
file.puts('# -*- encoding : utf-8 -*-') if RUBY_VERSION < '2.0.0'
|
367
|
+
file.puts(FILE_COMMENTS[:class])
|
368
|
+
object_hierarchy.each do |name, obj|
|
369
|
+
file.puts("#{indent}#{obj} #{name.split('::').last}")
|
370
|
+
indent += ' '
|
371
|
+
end
|
372
|
+
file.puts("#{indent}class #{sb.name.upcase} # rubocop:disable ClassLength")
|
373
|
+
indent += ' '
|
374
|
+
file.puts("#{indent}include Origen::Model")
|
375
|
+
file.puts('')
|
376
|
+
SUB_BLOCK_ATTRS.each do |attr, comment|
|
377
|
+
attr_sym = ":#{attr}"
|
378
|
+
# First check that the attribute has content
|
379
|
+
if sb.respond_to?(attr)
|
380
|
+
next if sb.send(eval(attr_sym)).nil?
|
381
|
+
file.puts("#{indent}# #{comment}")
|
382
|
+
file.puts("#{indent}attr_reader :#{attr}")
|
383
|
+
file.puts('')
|
384
|
+
end
|
385
|
+
end
|
386
|
+
file.puts("#{indent}def initialize(options = {})")
|
387
|
+
indent += ' '
|
388
|
+
SUB_BLOCK_ATTRS.keys.each do |attr|
|
389
|
+
case attr
|
390
|
+
when /base_address/
|
391
|
+
attr_var = ":@reg_#{attr}"
|
392
|
+
file.puts("#{indent}\@#{attr} = #{sb.instance_variable_get(eval(attr_var)).to_hex}")
|
393
|
+
else
|
394
|
+
attr_var = ":@#{attr}"
|
395
|
+
attr_sym = ":#{attr}"
|
396
|
+
# First check that the attribute has content
|
397
|
+
if sb.respond_to?(attr)
|
398
|
+
next if sb.send(eval(attr_sym)).nil?
|
399
|
+
if sb.instance_variable_get(eval(attr_var)).is_a?(String)
|
400
|
+
file.puts("#{indent}\@#{attr} = '#{sb.instance_variable_get(eval(attr_var))}'")
|
401
|
+
elsif sb.instance_variable_get(eval(attr_var)).is_a?(Symbol)
|
402
|
+
file.puts("#{indent}\@#{attr} = :#{sb.instance_variable_get(eval(attr_var))}")
|
403
|
+
else
|
404
|
+
file.puts("#{indent}\@#{attr} = #{sb.instance_variable_get(eval(attr_var))}")
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
file.puts("#{indent}instantiate_registers(options)")
|
410
|
+
indent = indent[0..-3]
|
411
|
+
file.puts("#{indent}end")
|
412
|
+
file.puts('')
|
413
|
+
file.puts("#{indent}# rubocop:disable LineLength")
|
414
|
+
# Need the register and bit_field descriptions to use double quotes
|
415
|
+
file.puts("#{indent}# rubocop:disable StringLiterals")
|
416
|
+
file.puts("#{indent}def instantiate_registers(options = {}) # rubocop:disable MethodLength")
|
417
|
+
indent += ' '
|
418
|
+
sb.regs.each do |_reg_name, r|
|
419
|
+
reg_addr_offset = (r.address - sb.base_address).to_hex
|
420
|
+
reg_path = r.path.gsub(/#{klass}./i, '')
|
421
|
+
reg_path.chop! if reg_path[-1] == '.'
|
422
|
+
r.description.each do |line|
|
423
|
+
file.puts("#{indent}# #{line}")
|
424
|
+
end
|
425
|
+
reg_string = "#{indent}reg :#{r.name}, #{reg_addr_offset}, size: #{r.size}"
|
426
|
+
if r.respond_to? :bit_order
|
427
|
+
if r.bit_order.is_a?(String)
|
428
|
+
reg_string += ", bit_order: '#{r.bit_order}'"
|
429
|
+
elsif r.bit_order.is_a?(Symbol)
|
430
|
+
reg_string += ", bit_order: :#{r.bit_order}"
|
431
|
+
elsif r.bit_order.is_a?(NilClass)
|
432
|
+
# do not add bitorder if it is not available
|
433
|
+
else
|
434
|
+
reg_string += ", bit_order: #{r.bit_order}"
|
435
|
+
end
|
436
|
+
end
|
437
|
+
if r.respond_to? :space
|
438
|
+
if r.space.is_a?(String)
|
439
|
+
reg_string += ", space: '#{r.space}'"
|
440
|
+
elsif r.space.is_a?(Symbol)
|
441
|
+
reg_string += ", space: :#{r.space}"
|
442
|
+
else
|
443
|
+
reg_string += ", space: #{r.space}"
|
444
|
+
end
|
445
|
+
end
|
446
|
+
file.puts("#{reg_string} do |reg|")
|
447
|
+
indent += ' '
|
448
|
+
r.named_bits do |field, bits|
|
449
|
+
plain_bit_description = Nokogiri::HTML(bits.description.join(' ').to_s).text
|
450
|
+
plain_bit_description.gsub!(/"/, "'")
|
451
|
+
if bits.size > 1
|
452
|
+
bit_index = "#{bits.position + bits.size - 1}..#{bits.position}"
|
453
|
+
else
|
454
|
+
bit_index = bits.position.to_s
|
455
|
+
end
|
456
|
+
bits.description.each do |line|
|
457
|
+
file.puts("#{indent}# #{line}")
|
458
|
+
end
|
459
|
+
file.puts("#{indent}reg.bit #{bit_index}, :#{field}, reset: 0b#{bits.reset_val.to_s(2)}, access: :#{bits.access}")
|
460
|
+
end
|
461
|
+
indent = indent[0..-3]
|
462
|
+
file.puts("#{indent}end")
|
463
|
+
end
|
464
|
+
indent = indent[0..-3]
|
465
|
+
file.puts("#{indent}end")
|
466
|
+
indent = indent[0..-3]
|
467
|
+
file.puts("#{indent}end")
|
468
|
+
object_hierarchy.each do |_name, _obj|
|
469
|
+
indent = indent[0..-3]
|
470
|
+
file.puts("#{indent}end")
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
# Returns a hash (key == scope, value is 'module' or 'class') needed to
|
478
|
+
# reconstruct the application hierarchy
|
479
|
+
def get_namespace(options)
|
480
|
+
obj = options[:obj]
|
481
|
+
namespace = []
|
482
|
+
object_hierarchy = {}
|
483
|
+
namespace = obj.class.to_s.split('::')
|
484
|
+
namespace.pop if options[:class_name]
|
485
|
+
curr_eval = nil
|
486
|
+
scope = nil
|
487
|
+
namespace.each_with_index do |e, _i|
|
488
|
+
scope.nil? ? scope = e : scope += "::#{e}"
|
489
|
+
curr_eval = "#{scope}.class"
|
490
|
+
object_hierarchy["#{scope}"] = eval(curr_eval).to_s.downcase
|
491
|
+
end
|
492
|
+
if options[:class_name]
|
493
|
+
if object_hierarchy.empty?
|
494
|
+
object_hierarchy[options[:class_name]] = 'class'
|
495
|
+
else
|
496
|
+
object_hierarchy["#{object_hierarchy.keys.last}::#{options[:class_name]}"] = 'class'
|
497
|
+
end
|
498
|
+
end
|
499
|
+
object_hierarchy
|
500
|
+
end
|
501
|
+
|
502
|
+
# Returns a hash of all of the non-nil instance_variables for an instance
|
503
|
+
def instance_vars_with_content(obj)
|
504
|
+
ivars_content = {}
|
505
|
+
obj.instance_variables.each do |ivar|
|
506
|
+
ivar_sym = ivar.to_s.gsub('@', '').to_sym
|
507
|
+
# Check for reg_base_address as method base_address refers to this instance variable
|
508
|
+
# Could use reg_base_address but all docs show to use base_address in the sub_block calls
|
509
|
+
# If not reg_base_address the ivar must be included in SUB_BLOCK_ATTRS
|
510
|
+
next unless ivar_sym == :reg_base_address || SUB_BLOCK_ATTRS.include?(ivar_sym)
|
511
|
+
# Skip the instance variable if it is nil
|
512
|
+
next if obj.send(ivar_sym).nil?
|
513
|
+
if ivar_sym == :reg_base_address
|
514
|
+
ivars_content[:base_address] = obj.send(ivar_sym)
|
515
|
+
else
|
516
|
+
ivars_content[ivar_sym] = obj.send(ivar_sym)
|
517
|
+
end
|
518
|
+
end
|
519
|
+
ivars_content
|
520
|
+
end
|
521
|
+
|
522
|
+
# Recursively work through the object hierarchy and return the full class string
|
523
|
+
def get_full_class(obj)
|
524
|
+
class_str = ''
|
525
|
+
until obj.nil?
|
526
|
+
if obj == Origen.top_level
|
527
|
+
class_str.prepend @top_level_hierarchy.keys.last
|
528
|
+
else
|
529
|
+
# If the class method produces "SubBlock" then use the object name instead
|
530
|
+
if obj.class.to_s.split('::').last == 'SubBlock'
|
531
|
+
class_str.prepend "::#{obj.name.upcase}"
|
532
|
+
else
|
533
|
+
class_str.prepend "::#{obj.class.to_s.split('::').last}"
|
534
|
+
end
|
535
|
+
end
|
536
|
+
obj = obj.parent
|
537
|
+
end
|
538
|
+
class_str
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CrossOrigen
|
2
|
+
class Ralf
|
3
|
+
# Returns the object that included the CrossOrigen module
|
4
|
+
attr_reader :owner
|
5
|
+
|
6
|
+
def initialize(owner)
|
7
|
+
@owner = owner
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns a string representing the owner object in RALF format
|
11
|
+
def owner_to_ralf(options = {})
|
12
|
+
Origen.compile("#{Origen.root!}/templates/ralf/default.ralf.erb", options.merge(scope: owner))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CrossOrigen
|
2
|
+
module Test
|
3
|
+
# Simple DUT class used for testing
|
4
|
+
class DUT
|
5
|
+
include Origen::TopLevel
|
6
|
+
include CrossOrigen
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@path = :hidden
|
10
|
+
sub_block :atx, class_name: 'D_IP_ANA_TEST_ANNEX_SYN'
|
11
|
+
|
12
|
+
# Register defined solely to test out the top level register export
|
13
|
+
reg :dut_top_level_reg, 0x0, size: 32, bit_order: :msb0, lau: 8 do
|
14
|
+
bit 15, :pls_work, reset: 1, access: :rw
|
15
|
+
bit 14, :second_bit, reset: 0, access: :rw
|
16
|
+
end
|
17
|
+
# Register defined solely to test out the top level register export
|
18
|
+
reg :dut_top_level_reg_number_two, 0x10, size: 32, bit_order: :lsb0, lau: 16 do
|
19
|
+
bit 0, :pls_work, reset: 0, access: :ro
|
20
|
+
bit 1, :second_bit, reset: 1, access: :rw
|
21
|
+
end
|
22
|
+
# Import some data from IP-XACT
|
23
|
+
cr_import(path: "#{Origen.root}/imports/ipxact.xml")
|
24
|
+
end
|
25
|
+
|
26
|
+
class D_IP_ANA_TEST_ANNEX_SYN # rubocop:disable ClassAndModuleCamelCase
|
27
|
+
include Origen::Model
|
28
|
+
include CrossOrigen
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
# A manually defined register for testing the conversion of any specific attributes
|
32
|
+
|
33
|
+
# ** MGATE Clock Divider Register **
|
34
|
+
# The MCLKDIV register is used to divide down the frequency of the HBOSCCLK input. If the MCLKDIV
|
35
|
+
# register is set to value "N", then the output (beat) frequency of the clock divider is OSCCLK / (N+1). The
|
36
|
+
# resulting beats are, in turn, counted by the PTIMER module to control the duration of Flash high-voltage
|
37
|
+
# operations.
|
38
|
+
# This is a test of potentially problematic characters ' " \' \" < >
|
39
|
+
reg :mclkdiv, 0x0, size: 16, bit_order: 'decrement' do
|
40
|
+
# **Oscillator (Hi)** - Firmware FMU clk source selection. (Note that in addition to this firmware-controlled bit, the
|
41
|
+
# FMU clock source is also dependent on test and power control discretes).
|
42
|
+
#
|
43
|
+
# 0 | FMU clock is the externally supplied bus clock ipg_clk
|
44
|
+
# 1 | FMU clock is the internal oscillator from the TFS hardblock
|
45
|
+
bit 15, :osch, reset: 1, access: :rw
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|